win32汇编指导--部分
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(3)释放互斥锁
ReleaseMutex()函数对应于信号量的 “释放”操作。其原型为: ReleaseMutex proto hObject:DWORD hObject :同步对象(互斥锁、信号量、 事件等)的句柄。
4. 线程同步演示程序
(1)线程的创建 按下“开始计数”按钮后,程序创建了10个线程,每个线程 的编号为0~9,通过_lParam参数传递到线程函数中。 _ThreadWithSync、_ThreadWithoutSync的功能相同。每个 线程中执行的操作等价于:
2. 从临时任务切换到演示任务
TR未在实模式下设置,切换到保护模式后,要把 指向临时任务TSS描述符的选择符(TempTSS_Sel) 装入TR。 在任务切换时,把原任务的现场保存到TR所指示 的TSS内,然后再把指向目标任务的TSS描述符的 选择符装入TR。 在DemoTSSSeg中,演示任务TSS的CS字段存放 的是DemoCode_Sel,对应的描述符是DemoLDT 中的DemoCode,在切换到演示任务后从 DemoBegin开始执行。
程序中包括的内容:
(1) 实模式下的数据段(RDataSeg)。其中包括全局描述符 表GDT。 (2) 演示任务的LDT段(DemoLDTSeg)。 (3) 演示任务的TSS(DemoTSSSeg)。 (4) 演示任务的0级和2级堆栈段(DemoStack0Seg、 DemoStack2Seg)。 (5) 演示任务数据段(DemoDataSeg)。 (6) 子程序代码段(SubRSeg)。 (7) 演示任务代码段(DemoCodeSeg)。 (8) 临时任务的TSS段(TempTSSSeg)。 (9) 临时任务的代码段(TempCodeSeg)。 (10) 实模式下的堆栈段(RStackSeg)。 (11) 实模式下的代码段(RCodeSeg)。
-错误的执行过程
第1个线程在执行完“mov eax,dwCounter”后,线程被操作 系统挂起,切换到第2个线程,第2个线程执行时, dwCounter仍然为0,执行完毕后,dwCounter=1。这时, 再切换到第1个线程,eax从0增加到1,再保存到dwCounter 中,结果dwCounter=1。
(1)创建互斥锁
CreateMutex()函数可用来创建一个有名或无名的互斥锁对 象,其函数原型为:
CreateMutex proto lpMutexAttributes:DWORD,\ bInitialOwner:DWORD,\ lpName:DWORD
lpMutexAttributes:互斥锁的安全属性,置该值为NULL时, 使用缺省安全属性。 bInitialOwner:=TRUE时,表示创建后立即获取该互斥锁对 象;=FALSE时,仅创建该互斥锁,不获取该互斥锁对象。 lpName:字符串,互斥锁的名字。置该值为NULL时,创建 无名互斥锁对象。 如果成功执行,将返回一个互斥锁对象的句柄。
4. 从演示任务切换到临时任务
演示任务采用段间转移指令JMP,通过任务门 ToTempT切换到临时任务。演示任务的现场被 保存到演示任务的TSS;临时任务的现场从临 时任务的TSS恢复。 临时任务的挂起点是TempCodeSeg的“inc byte ptr es:[0h]”指令,所以恢复后的临时任务 从该指令处开始执行。在恢复到临时任务时, SS、DS、FS、GS被恢复为Normal_Sel,ES被 恢复为Video_Sel。
在DemoLDT中,含有以下局部描述符:
(1) 演示任务的0级和2级堆栈段描述符 (DemoStack0、DemoStack2) (2) 代码段描述符(DemoCode) (3) 数据段描述符(DemoData) (4) LDT所在数据段的描述符(ToDLDT) (5) 临时任务TSS所在数据段的描述符 (ToTTSS) (6) 指向子程序的调用门(ToSubR) (7) 指向临时任务的任务门(ToTempT)。 这些描述符只能被临时任务所使用。
程序执行过程:
(6) 从堆栈中取出入口参数并处理(SubRB); (7) 从显示信息子程序返回特权级为2的演示代 码段(ret 8); (8) 经任务门切换到特权级为0的临时任务 (JUMP32 ToTempT_Sel,0); (9) 循环执行(4)~(8)任务切换5次(loop指 令)。 (10) 切换到实模式(JUMP16 <SEG Real>,<OFFSET Real>); (11) 实模式下的恢复工作(Real)。
1. 实现步骤
第一个任务称为临时任务,另一个任务称为演示任 务。 临时任务的代码位于TempCodeSeg段,从标号 Virtual处开始执行;演示任务的代码位于 DemoCodeSeg段,从标号DemoBegin处开始执行。 演示任务还调用了SubRSeg段中的SubRB子程序。
模式切换 RCodeSeg (实模式) 任务切换 调用门 SubCodeSeg (保护模式)
1. 创建源自文库程
调用CreateThread函数创建新的线程,其参数如 下: CreateThread proto lpThreadAttributes:DWORD,\ dwStackSize:DWORD,\ lpStartAddress:DWORD,\ lpParameter:DWORD,\ dwCreationFlags:DWORD,\ lpThreadId:DWORD
TempCodeSeg (保护模式) 调用门
DemoCodeSeg (保护模式)
程序执行过程:
(1) 实模式下初始化(Start); (2) 切换到保护模式(JUMP16 <TempCode_Sel>,<OFFSET Virtual>指令); (3) 设置TR对应临时任务,特权级为0 (Virtual); (4) 直接切换到演示任务,演示任务的特权级 为2(JUMP16 DemoTSS_Sel,0); (5) 把入口参数压入堆栈,经调用门进入显示 信息子程序,显示信息子程序的特权级为0 (DemoBegin);
5. 任务现场的保存、恢复
程序在临时任务和演示任务之间进行了多次任务切换。临时 任务在进入时,清除屏幕内容,将屏幕左上角(0,0)处的字符 设为’0’。 演示任务执行一次,显示EDI的当前值。第1次执行时,EDI 的值等于(80*4+50)*2,即000002E4h,在屏幕上位置(4,50) 处显示“EDI=000002E4”,之后,EDI增加160,执行下一行。 在切换到临时任务时,EDI的值被保存到DemoTSSSeg中。 下一次从临时任务切换到演示任务时,EDI从DemoTSSSeg 中恢复,所以在屏幕上位置(5,50)处显示。 从临时任务切换到演示任务时,临时任务的ECX值也被保存 到TempTSSSeg中,切换回临时任务时,从TempTSSSeg恢 复ECX值,所以,循环一共执行5次,每次将屏幕左上角(0,0) 处的字符加1。执行结束时,该字符变为’5’。
-创建线程的属性
lpThreadAttributes:线程的安全属性,置该值为NULL 时,使用缺省的安全属性。 dwStackSize:线程的堆栈大小。如果为0,使用和进 程相同大小的堆栈。 lpStartAddress:线程函数的起始地址。 lpParameter:传递给线程的上下文。可以是一个整数, 或者一个指向某个结构的指针,通过lpParameter将参 数传递给线程。 dwCreationFlags:=0表示创建线程后立即启动; =CREATE_SUSPENDED时,需要调用ResumeThread() 函数启动该线程。 lpThreadId:指向一个双字,用于保存线程ID。
dwCounter++; dwCounter--;
每一次的操作作为一轮计数,计数的轮数保存在dwRounds 中。 ThreadWithSync在更新dwCounter、dwRounds时,使用互 斥锁hMutexCounter、hMutexRounds进行了保护。而 ThreadWithoutSync未使用互斥锁。
(2)获取互斥锁
WaitForSingleObject()函数对应于信号量的“获得” 操作。其原型为: WaitForSingleObject proto hObject:DWORD, dwTimeout:DWORD hObject :同步对象(互斥锁、信号量、事件等) 的句柄。 dwTimeout :等待同步对象变成“有信号”前的 最长时间,以毫秒计。当等待的时间超过该值后, WaitForSingleObject函数返回,不再等待。如果想 要线程一直等待到同步对象变成“有信号”,该 参数设为INFINITE(该值等于0xffffffff)
2. 线程同步问题
线程能够共享进程的资源,包括数据区中的全 局变量。多个线程存取同一个全局变量,,必 须考虑同步的问题。例如,我们创建了2个线 程,每个线程在函数中执行以下3条指令: mov eax,dwCounter add eax,1 mov dwCounter,eax dwCounter的初值为0,每个线程各执行一次, 最后的结果应该是dwCounter=2。但是,由于 线程执行的并发性,其结果并不一定等于2。
3. 互斥锁
互斥锁是一种特殊的信号量。信号量中有一个 计数器,信号量有2个操作:“获得”、“释 放”。为“获得”信号量,如果信号量的当前 值为 0,那么线程就阻塞,直到计数器值大于 0为止。之后,该计数器值减 1。“释放”信 号量时,该计数器值加 1。 互斥锁是那些值只能为 0 或 1 的信号量。一个 互斥锁可以作为一个“令牌”,每次只允许一 个线程访问共享的全局变量。互斥锁用于线程 之间的互相排斥:在任何一个时刻,只有一个 线程可以“拥有”一个互斥锁。
3. 演示任务内的特权级变换
演示任务采用段间调用指令CALL,通过调用门ToSubR调用 子程序SubRB。调用门ToSubR内的SubR_Sel所指示的子程 序代码段描述符(SubR)的DPL=0,所以在调用过程中就发 生了从特权级2到特权级0的变换,同时堆栈也被切换到 DemoStack0Seg。 通过堆栈传递了两个参数给子程序SubRB。在把参数压入堆 栈时,CPL=2,使用的也是对应特权级2 的堆栈 (DemoStack2Seg)。通过调用门进入子程序后,CPL=0, 使用0级堆栈。为此,把调用门ToSubR中的DCount字段设置 为2,提升到特权级0时,CPU从DemoStack2Seg复制了2个 双字参数到DemoStack0Seg。 从子程序SubRB返回时,CPL=0变换为CPL=2,堆栈也回到2 级堆栈(DemoStack2Seg)。
汇编语言程序设计
实验11 多任务和多线程
提纲
11.1 多任务及其调度 11.2 多线程编程 11.3 X86-64架构简介
11.1 多任务及其调度
下面给出一个用于演示任务切换的实例。 该程序在保护模式下建立2个任务,分别 在屏幕上显示单个字符和寄存器的值。 涉及的内容包括:直接通过TSS段的任务 切换,通过任务门的任务切换,任务内 特权级的变换及参数传递。
程序清单: task.asm(任务切换)
程序源文件 task.asm
11.2 多线程编程
运行一个可执行文件时,Windows操作系统会创建 一个进程,为该进程生成私有内存地址空间(包括 代码区、数据区、堆栈区),把磁盘上的可执行文 件映射到该空间上。接着,操作系统自动地为该进 程创建一个主线程,主线程通常从可执行文件的第 一条指令处开始执行。 除了主线程外,在程序中创建新的线程,创建出的 线程和主线程在同一个进程环境中执行,共享相同 的私有内存地址空间、全局变量、资源、文件句柄 等。但是,每一个线程都有一个独立的堆栈。 利用线程能够并发运行的特点,可以将一个应用程 序内的具体操作分成若干个线程。