CLR初始化及EXE加载的流程

本文详细介绍了托管PE文件(如托管EXE和DLL文件)如何通过特定的x86存根函数来初始化CLR并确定托管入口点方法的过程。此外,还讨论了不同Windows操作系统版本下托管PE文件的不同加载方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

When the compiler/linker creates an executable assembly, the following 6−byte x86 stub function is emitted into the PE file’s .text section:
JMP _CorExeMain
Because the _CorExeMain function is imported from Microsoft’s MSCorEE.dll dynamic−link library,MSCorEE.dll is referenced in the assembly file’s import (.idata) section. MSCorEE.dll stands for Microsoft Component Object Runtime Execution Engine. When the managed EXE file is invoked,Windows treats it just like any normal (unmanaged) EXE file: the Windows loader loads the file and examines the .idata section to see that MSCorEE.dll should be loaded into the process’s address space. Then the loader obtains the address of the _CorExeMain function inside MSCorEE.dll and fixes up the stub function’s JMP instruction in the managed EXE file.
The process’s primary thread begins executing this x86 stub function, which immediately jumps to _CorExeMain in MSCorEE.dll. _CorExeMain initializes the CLR and then looks at the executable assembly’s CLR header to determine what managed entry point method should execute. The IL code for the method is then compiled into native CPU instructions, and the CLR jumps to the native code (using the process’s primary thread). At this point, the managed application’s code is running.
The situation is similar for a managed DLL. When building a managed DLL, the compiler/linker emits a similar 6−byte x86 stub function in the PE file’s .text section for a DLL assembly:
JMP _CorDllMain

The _CorDllMain function is also imported from the MSCorEE.dll, causing the DLL’s .idata section to reference MSCorEE.dll. When Windows loads the DLL, it will automatically load MSCorEE.dll (if it isn’t already loaded), obtain the address of the _CorDllMain function, and fix up the 6−byte x86 JMP stub in the managed DLL. The thread that called LoadLibrary to load the managed DLL now jumps to the x86 stub in the managed DLL assembly, which immediately jumps to the _CorDllMain function in MSCorEE.dll. _CorDllMain initializes the CLR (if it hasn’t already been initialized for the process) and then returns so that the application can continue executing as normal.

These 6−byte x86 stub functions are required to run managed assemblies on Windows 98,Windows 98 Standard Edition, Windows Me, Windows NT 4, and Windows 2000 because all these operating systems shipped long before the CLR became available. Note that the 6−byte stub function is specifically for x86 machines. This stub doesn’t work properly if the CLR is ported to run on other CPU architectures. Because Windows XP and the Windows .NET Server Family support both the x86 and the IA64 CPU architectures, Windows XP and the Windows .NET Server Family loader was modified to look specifically for managed assemblies.
On Windows XP and the Windows .NET Server Family, when a managed assembly is invoked (typically via CreateProcess or LoadLibrary), the OS loader detects that the file contains managed code by examining directory entry 14 in the PE file header. (See IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR in WinNT.h.) If this directory entry exists and is not 0, the loader ignores the file’s import (.idata) section and automatically loads MSCorEE.dll into the process’s address space. Once loaded, the OS loader makes the process’s thread jump directly to the correct function in MSCorEE.dll. The 6−byte x86 stub functions are ignored on machines running Windows XP and the Windows .NET Server Family.
One last note on managed PE files: they always use the 32 bit PE file format, not the 64−bit PE file format. On 64−bit Windows systems, the OS loader detects the managed 32−bit PE file and automatically knows to create a 64−bit address space.

图:


### PWM 初始化实现方法 PWM(脉宽调制)是一种通过调整信号占空比来控制输出的技术,在嵌入式系统中广泛用于电机控制、LED亮度调节等领域。以下是几种常见的PWM初始化方式及其代码示例。 #### 嵌入式C语言中的PWM初始化 对于基于ARM Cortex-M或其他微控制器的项目,通常需要手动配置寄存器以完成PWM初始化。以下是一个典型的LPC40XX芯片上的PWM初始化代码: ```c #define Error1 1001 unsigned int Error_flag; /* 名称:void Fan_PWM_Init(void) * 功能:实现MotorPWM基本初始化 * 参数:无 * 返回值:无 */ void Fan_PWM_Init(void) { PCON_bit.BODPDM = 1; // 打开风扇PWM功率控制口; IOCON_P1_25 = 4; // 配置GPIO为PWM功能 MCCON_CLR_bit.RUN1 = 1; // 关闭定时器运行状态 MCCON_SET_bit.POLA1 = 1; // 设置极性,默认边沿对齐 MCLIM0 = Timer_Motor; // 设置PWM周期 MCMAT0 = 0; // 设置初始占空比为0% MCCNTCON_CLR_bit.CNTR1 = 1; // 设置计数器模式为增减计数 MCCON_SET_bit.RUN1 = 1; // 开启定时器运行 } ``` 此代码片段展示了如何针对特定硬件平台(如LPC40XX系列MCU)进行PWM初始化[^2]。它涉及多个寄存器操作,包括但不限于`IOCON`端口配置、`MCCON`控制寄存器以及`MCLIM/MCMAT`等与PWM波形生成相关的寄存器。 --- #### Python 中的 RPi.GPIO PWM 实现 在树莓派平台上,可以通过 `RPi.GPIO` 模块轻松实现PWM功能。下面是一段简单的Python代码示例,展示如何使用该模块创建并启动一个PWM实例: ```python import RPi.GPIO as GPIO import time # 定义引脚编号 pin_pwm = 18 # 初始化GPIO环境 GPIO.setmode(GPIO.BCM) GPIO.setup(pin_pwm, GPIO.OUT) # 创建PWM对象,频率设为50Hz pwm = GPIO.PWM(pin_pwm, 50) try: # 启动PWM,初始占空比为0% pwm.start(0) while True: for dc in range(0, 101, 5): # 占空比从0%到100%,步长为5% pwm.ChangeDutyCycle(dc) time.sleep(0.1) for dc in range(100, -1, -5): # 占空比从100%回到0% pwm.ChangeDutyCycle(dc) time.sleep(0.1) except KeyboardInterrupt: pass finally: pwm.stop() # 停止PWM GPIO.cleanup() # 清理GPIO资源 ``` 这段代码利用了 `RPi.GPIO` 提供的功能,能够快速搭建起基础的PWM控制系统[^3]。需要注意的是,由于软件层面的时间片分配机制,这种方式可能无法达到高精度需求的应用场景[^4]。 --- #### Linux 下 SYSFS 接口的 PWM 控制 如果目标是在Linux环境下工作,则可通过SYSFS接口直接访问底层硬件资源而无需编写复杂的驱动程序。具体步骤如下所示: 1. **加载内核模块** 确保已启用对应外设的支持,并加载必要驱动。 2. **导出指定通道** 使用命令行工具将所需PWM通道暴露给用户空间: ```bash echo <channel> > /sys/class/pwm/<chip>/export ``` 3. **设置参数** 调整周期长度及占空时间比例: ```bash echo <period_ns> > /sys/class/pwm/<chip>:<channel>/period echo <duty_cycle_ns> > /sys/class/pwm/<chip>:<channel>/duty_cycle ``` 4. **使能输出** 最后一步激活实际信号输出: ```bash echo 1 > /sys/class/pwm/<chip>:<channel>/enable ``` 以上流程适用于大多数支持标准API定义的操作系统版本[^5]。当然,不同厂商可能会有所定制化改动,请参照官方文档确认细节部分。 --- ### 总结 无论是采用传统裸机开发还是现代高级语言封装形式,都可以找到适合自己的解决方案来进行有效的PWM管理。每种途径都有其优缺点,开发者应根据实际情况灵活选用最佳策略。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值