debug版函数初始化入口 0xcc

本文深入解析了在VC++编写的程序中Debug版函数入口处常见的一段代码,详细解释了其作用在于开辟局部变量栈空间、保护关键寄存器并初始化栈内存为0xCC,旨在提供对错误处理、调试和shellcode分析的洞察。

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

在VC++编写的程序编程成Debug版,反汇编代码,函数入口处经常看到如下一段代码:

00EA14E0 55                push        ebp  
00EA14E1 8B EC             mov         ebp,esp
00EA14E3 81 EC C0 00 00 00 sub         esp,0C0h
00EA14E9 53                push        ebx  
00EA14EA 56                push        esi  
00EA14EB 57                push        edi  
00EA14EC 8D BD 40 FF FF FF lea         edi,[ebp-0C0h]
00EA14F2 B9 30 00 00 00    mov         ecx,30h
00EA14F7 B8 CC CC CC CC    mov         eax,0CCCCCCCCh
00EA14FC F3 AB             rep stos    dword ptr es:[edi]

其中主要分为3部分,最上面3行完成本函数局部变量栈空间的开辟,中间部分保存需要保护的寄存器(这部分并非必须),最后4行完成栈空间所有字节初始化为0xCC。

0xCC对应汇编代码 int 3,即软中断。

一方面,0xCC可以为某些检查提供标记(_RTC_CheckStackVars);另一方面,在栈操作错误或调试汇编代码(如使用OD调试shellcode)时可以对感兴趣的逻辑进行细致的分析,这通常可以通过加入

__asm {

       int 3  ;         // 或 _emit 0xcc

};

来加入断点。

我正在完成一个OpenHarmony的嵌入式设计项目,功能要求 1.能够使用交通灯板上的蜂蜜器播放选定的曲谱, PWM原理、音符--频率对应关系、音符频率选择、曲谱电子化(转程序数组)、程序逻辑、BUILD.gn出国文件修改、代码编译、固件烧录、串口调试、运行测试等都能在报告中清晰说明、项目答辩阐述清楚、答辩提问回答基本正确。 2. 能够使用交通灯板上的按键切换播放的曲谱, 至少有两首或以上曲谱可以切换(曲谱越多得分越高)、播放出的曲谱音律基本准确。 3. 能够应用OLED显示屏显示当前播放曲谱的相关信息, 能够显示当前播放曲谱的名气、歌词等相关信息。 要求使用vscode中的海思环境和虚拟机Linux系统,硬件设备润和鸿蒙系统的满天星智能家居开发套件。 现在我已经完成了播放音乐,OLED显示歌名,播放音乐时交通板红绿灯闪烁的功能。 实现的代码如下: \applications\sample\wifi-iot\app\pwm_demo\display.c: #include <stdio.h> // 标准输入输出 #include <unistd.h> // POSIX标准接口 #include "ohos_init.h" // 用于初始化服务(services)和功能(features) #include "cmsis_os2.h" // CMSIS-RTOS API V2 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口-GPIO #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-IO #include "hi_adc.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-ADC #include "oled_ssd1306.h" // OLED显示屏简化驱动接口文件 // 定义一个宏,用于标识ADC2通道 #define ANALOG_KEY_CHAN_NAME HI_ADC_CHANNEL_2 // 使用PCtoLCD建立字库 // 字符集:铃铛 // 字符轮廓:16 X 16,新宋体 // 每个字32个字节(16*16/8=32) // 根据取模方式,每个字的前16字节是汉字的上半部分,后16字节是汉字的下半部分 // 使用二维数组 uint8_t fonts1[][32] = { {0x40,0x30,0xEF,0x24,0x24,0x40,0x20,0x10,0x0C,0x23,0xCC,0x10,0x20,0x40,0x40,0x00,0x01,0x01,0x7F,0x21,0x11,0x00,0x01,0x09,0x11,0x21,0xD1,0x0D,0x03,0x00,0x00,0x00},/*"铃",0*/ {0x20,0x10,0x2C,0xE7,0x24,0x24,0x40,0x42,0x5C,0x40,0x7F,0x40,0x50,0xCE,0x00,0x00,0x01,0x01,0x01,0x7F,0x21,0x11,0x40,0x44,0x44,0x44,0x44,0x44,0x44,0xFF,0x00,0x00},/*"铛",1*/ }; /// @brief 显示一个汉字(使用PCtoLCD建立的字库) /// @param x x坐标,1像素为单位 /// @param y y坐标,8像素为单位。即页面起始地址 /// @param idx 汉字在字库中的索引 void OledShowChinese1(uint8_t x, uint8_t y, uint8_t idx) { // 控制循环 uint8_t t; // 显示汉字的上半部分 OledSetPosition(x, y); for (t = 0; t < 16; t++) { WriteData(fonts1[idx][t]); } // 显示汉字的下半部分 OledSetPosition(x, y + 1); for (t = 16; t < 32; t++) { WriteData(fonts1[idx][t]); } } // 主线程函数 static void OledTask(void *arg) { (void)arg; // 初始化SSD1306显示屏驱动芯片 OledInit(); // 全屏填充黑色 OledFillScreen(0x00); // 显示"铃铛" // 起始x坐标 = (屏幕宽度128 - (汉字间距18*(字数-1) + 每个汉字的宽度16 - 第一个汉字的坐标0))/2 = 29 OledShowChinese1(29 + 0, 3, 0); //铃 OledShowChinese1(29 + 18, 3, 1); //铛 // 居中显示"OpenHarmony" // 起始x坐标 = (屏幕宽度128 - 字符间距8 * 字母个数11)/2 = 20 OledShowString(20, 5, "OpenHarmony", FONT8x16); // 左上角显示倒计时 char digits[] = "8 7 6 5 4 3 2 1"; for (int i = 0; i < 15; i++) { OledShowChar(0, 0, digits[i], FONT6x8); sleep(1); } // 中英文混杂显示 OledFillScreen(0x00); // 全屏填充黑色 // 工作循环 while (1) { // 要显示的字符串 static char text[128] = {0}; // 用于存放ADC2通道的值 unsigned short data = 0; // 读取ADC2通道的值 hi_adc_read(ANALOG_KEY_CHAN_NAME, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0); OledShowString(36, 0, text, FONT8x16); // 等待30ms usleep(30 * 1000); } } // 入口函数 static void OledDemo(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "OledTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 4096; attr.priority = osPriorityNormal; // 创建线程 if (osThreadNew(OledTask, NULL, &attr) == NULL) { printf("[OledDemo] Falied to create OledTask!\n"); } } // 运行入口函数 APP_FEATURE_INIT(OledDemo); \applications\sample\wifi-iot\app\pwm_demo\music2.c: #include <stdio.h> // 标准输入输出头文件 #include <string.h> // 字符串处理头文件 #include "ohos_init.h" // 用于初始化服务(service)和功能(feature)的头文件 #include "cmsis_os2.h" // CMSIS-RTOS2头文件 #include "iot_gpio.h" // OpenHarmony API:IoT硬件设备操作接口中的GPIO接口头文件 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的IO接口头文件 #include "hi_pwm.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的PWM接口头文件 #include "ssd1306.h" // OLED显示屏驱动头文件 // 分频倍数数组 // 40MHz 对应的分频倍数 static const uint16_t g_tuneFreqs[] = { 0, // 不使用 38223, // 1046.5Hz C6(do) 34052, // 1174.7Hz D6(re) 30338, // 1318.5Hz E6(mi) 28635, // 1396.9Hz F6(fa) 25511, // 1568Hz G6(so) 22728, // 1760Hz A6(la) 20249, // 1975.5Hz B6(si) 51020 // 784Hz G5(so)低八度 }; // 曲谱音符数组:《铃儿响叮当》 static const uint8_t g_scoreNotes[] = { // 第一句: 3, 3, 3, 3, 3, 3, 3, 5, 1, 2, 3, // 第二句: 4, 4, 4, 4, 3, 3, 3, 2, 2, 1, 2, 5, // 第三句(重复第一句): 3, 3, 3, 3, 3, 3, 3, 5, 1, 2, 3, // 第四句: 4, 4, 4, 4, 3, 3, 5, 5, 4, 2, 1 }; // 曲谱时值数组:(单位:1/4拍,4=1拍,8=2拍) static const uint8_t g_scoreDurations[] = { // 第一句:三连音用短时值,结尾音稍长 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 4, // 第二句: 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 2, 4, // 第三句: 2, 2, 4, 2, 2, 4, 2, 2, 2, 2, 4, // 第四句: 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 4 }; // 主线程函数 static void BeeperMusicTask(void *arg) { (void)arg; printf("BeeperMusicTask start!\r\n"); // 日志输出 // 初始化OLED显示屏 ssd1306_Init(); ssd1306_Fill(Black); // 清屏 ssd1306_SetCursor(20, 2); // 设置光标位置 ssd1306_PrintString("送别", Font_11x18, White); // 显示歌曲名称 ssd1306_UpdateScreen(); // 更新显示 hi_pwm_set_clock(PWM_CLK_XTAL); // 设置时钟源为外部晶体时钟(40MHz,默认时钟源频率为160MHz) // 演奏音乐 // 使用循环遍历曲谱音符数组 for (size_t i = 0; i < sizeof(g_scoreNotes)/sizeof(g_scoreNotes[0]); i++) { // 获取音符,也就是分频倍数数组元素的下标 uint32_t tune = g_scoreNotes[i]; // 获取分频倍数 uint16_t freqDivisor = g_tuneFreqs[tune]; // 获取音符时间 // 适当拉长时间,四分之一拍用时125ms,每小节用时2s uint32_t tuneInterval = g_scoreDurations[i] * (125*1000); // 日志输出 printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval); if (tune != 0) { // 0表示休息 // 开始输出PWM信号,占空比为50% hi_pwm_start(HI_PWM_PORT_PWM0, freqDivisor/2, freqDivisor); } // 等待音符时间,参数的单位是微秒(千分之一毫秒) usleep(tuneInterval); // 停止输出PWM信号 hi_pwm_stop(HI_PWM_PORT_PWM0); // 停止一个音符后,等待20ms,让两次发音有个间隔,听起来更自然一些 usleep(20*1000); } // 播放完成后显示结束信息 ssd1306_Fill(Black); // 清屏 ssd1306_SetCursor(10, 2); ssd1306_UpdateScreen(); } // 入口函数 static void StartBeepMusicTask(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "BeeperMusicTask"; attr.stack_size = 4096; attr.priority = osPriorityNormal; // 设置蜂鸣器引脚的功能为PWM IoTGpioInit(HI_IO_NAME_GPIO_9); hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT); IoTGpioSetDir(HI_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT); IoTPwmInit(HI_PWM_PORT_PWM0); // 创建线程 if (osThreadNew(BeeperMusicTask, NULL, &attr) == NULL) { printf("[BeeperMusicExample] Falied to create BeeperMusicTask!\n"); } } // 运行入口函数 SYS_RUN(StartBeepMusicTask); \applications\sample\wifi-iot\app\pwm_demo\oled_ssd1306.h: // OLED显示屏简化驱动接口文件 // 定义条件编译宏,防止头文件的重复包含和编译 #ifndef OLED_SSD1306_H #define OLED_SSD1306_H #include <stdint.h> // 定义了几种扩展的整数类型和宏 // 声明接口函数 uint32_t OledInit(void); void OledSetPosition(uint8_t x, uint8_t y); void OledFillScreen(uint8_t fillData); uint32_t WriteData(uint8_t data); // 定义字库类型 enum Font { FONT6x8 = 1, FONT8x16 }; typedef enum Font Font; // 声明接口函数 void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font); void OledShowString(uint8_t x, uint8_t y, const char* str, Font font); // 条件编译结束 #endif // OLED_SSD1306_H \applications\sample\wifi-iot\app\pwm_demo\oled_ssd1306.c: // OLED显示屏简化驱动源文件 #include <stdio.h> // 标准输入输出 #include <stddef.h> // 标准类型定义 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口-GPIO #include "iot_i2c.h" // OpenHarmony HAL:IoT硬件设备操作接口-I2C #include "iot_errno.h" // OpenHarmony HAL:IoT硬件设备操作接口-错误代码定义 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口-IO // 字库头文件 #include "oled_fonts.h" // OLED显示屏简化驱动接口文件 #include "oled_ssd1306.h" // 定义一个宏,用于计算数组的长度 #define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0]) // 定义一个宏,用于标识I2C0 #define OLED_I2C_IDX 0 // 定义一个宏,用于标识I2C0的波特率(传输速率) #define OLED_I2C_BAUDRATE (400 * 1000) // 400KHz // 定义一个宏,用于标识OLED的宽度 #define OLED_WIDTH (128) // 定义一个宏,用于标识SSD1306显示屏驱动芯片的设备地址 #define OLED_I2C_ADDR 0x78 // 定义一个宏,用于标识写命令操作 #define OLED_I2C_CMD 0x00 // 0000 0000 写命令 // 定义一个宏,用于标识写数据操作 #define OLED_I2C_DATA 0x40 // 0100 0000(0x40) 写数据 // 定义一个宏,用于标识100ms的延时 #define DELAY_100_MS (100 * 1000) // 定义一个结构体,表示要发送或接收的数据 typedef struct { // 要发送的数据的指针 unsigned char *sendBuf; // 要发送的数据长度 unsigned int sendLen; // 要接收的数据的指针 unsigned char *receiveBuf; // 要接收的数据长度 unsigned int receiveLen; } IotI2cData; /// @brief 向OLED写一个字节 /// @param regAddr 写入命令还是数据 OLED_I2C_CMD / OLED_I2C_DATA /// @param byte 写入的内容 /// @retval 成功返回IOT_SUCCESS,失败返回IOT_FAILURE static uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte) { // 定义字节流 uint8_t buffer[] = {regAddr, byte}; IotI2cData i2cData = {0}; i2cData.sendBuf = buffer; i2cData.sendLen = sizeof(buffer) / sizeof(buffer[0]); // 发送字节流 return IoTI2cWrite(OLED_I2C_IDX, OLED_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen); } /// @brief 向OLED写一个命令字节 /// @param cmd 写入的命令字节 /// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE static uint32_t WriteCmd(uint8_t cmd) { return I2cWiteByte(OLED_I2C_CMD, cmd); } /// @brief 向OLED写一个数据字节 /// @param cmd 写入的数据字节 /// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE uint32_t WriteData(uint8_t data) { return I2cWiteByte(OLED_I2C_DATA, data); } /// @brief 初始化SSD1306显示屏驱动芯片 uint32_t OledInit(void) { // 构造初始化代码 static const uint8_t initCmds[] = { 0xAE, // 显示关闭 0x00, // 页寻址模式时,设置列地址的低4位为0000 0x10, // 页寻址模式时,设置列地址的高4位为0000 0x40, // 设置起始行地址为第00xB0, // 页寻址模式时,设置页面起始地址为PAGE0 0x81, // 设置对比度 0xFF, // 对比度数值 0xA1, // set segment remap 0xA6, // 设置正常显示。0对应像素熄灭,1对应像素亮起 0xA8, // --set multiplex ratio(1 to 64) 0x3F, // --1/32 duty 0xC8, // Com scan direction 0xD3, // -set display offset 0x00, // 0xD5, // set osc division 0x80, // 0xD8, // set area color mode off 0x05, // 0xD9, // Set Pre-Charge Period 0xF1, // 0xDA, // set com pin configuartion 0x12, // 0xDB, // set Vcomh 0x30, // 0x8D, // set charge pump enable 0x14, // 0xAF, // 显示开启 }; // 初始化GPIO-13 IoTGpioInit(HI_IO_NAME_GPIO_13); // 设置GPIO-13引脚功能为I2C0_SDA hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA); // 初始化GPIO-14 IoTGpioInit(HI_IO_NAME_GPIO_14); // 设置GPIO-14引脚功能为I2C0_SCL hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL); // 用指定的波特速率初始化I2C0 IoTI2cInit(OLED_I2C_IDX, OLED_I2C_BAUDRATE); // 发送初始化代码,初始化SSD1306显示屏驱动芯片 for (size_t i = 0; i < ARRAY_SIZE(initCmds); i++) { // 发送一个命令字节 uint32_t status = WriteCmd(initCmds[i]); if (status != IOT_SUCCESS) { return status; } } // OLED初始化完成,返回成功 return IOT_SUCCESS; } /// @brief 设置显示位置 /// @param x x坐标,1像素为单位 /// @param y y坐标,8像素为单位。即页面起始地址 /// @return 无 void OledSetPosition(uint8_t x, uint8_t y) { //设置页面起始地址 WriteCmd(0xb0 + y); // 列:0~127 // 第0列:0x00列,二进制00000000。低地址0000,即0x00。高地址0000(需要|0x10),0000|0x10=0x10。 // 第127列:0x7f列,二进制01111111。低地址1111,即0x0F。高地址0111(需要|0x10),0111|0x10=0x17。 // 设置显示位置:列地址的低4位 // 直接取出列地址低4位作为命令代码的低4位,命令代码的高4位为0000 WriteCmd(x & 0x0f); // 设置显示位置:列地址的高4位 // 取出列地址高4位作为命令代码的低4位,命令代码的高4位必须为0001 // 实际编程时,列地址的高4位和0x10(二进制00010000)进行按位或即得到命令代码 WriteCmd(((x & 0xf0) >> 4) | 0x10); } /// @brief 全屏填充 /// @param fillData 填充的数据,1字节 /// @return 无 void OledFillScreen(uint8_t fillData) { // 相关变量,用于遍历page和列 uint8_t m = 0; uint8_t n = 0; // 写入所有页的数据 for (m = 0; m < 8; m++) { //设置页地址:0~7 WriteCmd(0xb0 + m); // 设置显示位置为第0列 WriteCmd(0x00); //设置显示位置:列低地址(0000) WriteCmd(0x10); //设置显示位置:列高地址(0000) // 写入128列数据 // 在一个页中,数据按列写入,一次一列,对应发送过来的1字节数据 for (n = 0; n < 128; n++) { // 写入一个字节数据 WriteData(fillData); } } } /// @brief 显示一个字符 /// @param x: x坐标,1像素为单位 /// @param y: y坐标,8像素为单位 /// @param ch: 要显示的字符 /// @param font: 字库 void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font) { // 数组下标 uint8_t c = 0; // 循环控制 uint8_t i = 0; // 得到数组下标 // 空格的ASCII码32,在字库中的下标是0。字库中的字符-空格即相应的数组下标 c = ch - ' '; // 显示字符 if (font == FONT8x16) // 8*16的点阵,一个page放不下 { // 显示字符的上半部分 // 设置显示位置 OledSetPosition(x, y); // 逐个字节写入(16个数组元素的前8个) for (i = 0; i < 8; i++) { WriteData(F8X16[c * 16 + i]); } // 显示字符的下半部分 // 设置显示位置为下一个PAGE OledSetPosition(x, y + 1); // 逐个字节写入(16个数组元素的后8个) for (i = 0; i < 8; i++) { WriteData(F8X16[c * 16 + 8 + i]); } } else // 6*8的点阵,在一个page中 { // 设置显示位置 OledSetPosition(x, y); // 逐个字节写入(数组第二维的6个数组元素) for (i = 0; i < 6; i++) { WriteData(F6x8[c][i]); } } } /// @brief 显示一个字符串 /// @param x: x坐标,1像素为单位 /// @param y: y坐标,8像素为单位 /// @param str: 要显示的字符串 /// @param font: 字库 void OledShowString(uint8_t x, uint8_t y, const char *str, Font font) { // 字符数组(字符串)下标 uint8_t j = 0; // 检查字符串是否为空 if (str == NULL) { printf("param is NULL,Please check!!!\r\n"); return; } // 遍历字符串,显示每个字符 while (str[j]) { // 显示一个字符 OledShowChar(x, y, str[j], font); // 设置字符间距 x += 8; // 如果下一个要显示的字符超出了OLED显示的范围,则换行 if (x > 120) { x = 0; y += 2; } // 下一个字符 j++; } } \applications\sample\wifi-iot\app\pwm_demo\traffic_light.c: // Pegasus交通灯板三色灯与主控芯片引脚的对应关系 // GPIO_10 连接红色LED灯,输出高电平点亮 // GPIO_11 连接绿色LED灯,输出高电平点亮 // GPIO_12 连接黄色LED灯,输出高电平点亮 #include <stdio.h> // 标准输入输出头文件 #include <unistd.h> // POSIX头文件 #include "ohos_init.h" // 用于初始化服务(service)和功能(feature)的头文件 #include "cmsis_os2.h" // CMSIS-RTOS2头文件 #include "iot_gpio.h" // OpenHarmony HAL:IoT硬件设备操作接口中的GPIO接口头文件 #include "hi_io.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的IO接口头文件 #include "hi_pwm.h" // 海思 Pegasus SDK:IoT硬件设备操作接口中的PWM接口头文件 // 定义GPIO引脚,尽量避免直接用数值 #define BUTTON_GPIO 8 // 按钮 #define RED_GPIO 10 // 红色LED灯 #define GREEN_GPIO 11 // 绿色LED灯 #define YELLOW_GPIO 12 // 黄色LED灯 // 定义三色LED灯的状态 static int g_ledStates[3] = {0, 0, 0}; // 当前点亮的灯 static int g_currentBright = 0; // 主线程函数 static void *TrafficLightTask(const char *arg) { (void)arg; // 输出提示信息 printf("TrafficLightTask start!\r\n"); // 将三色灯的GPIO引脚放入数组,以便使用循环进行控制 unsigned int pins[] = {RED_GPIO, GREEN_GPIO, YELLOW_GPIO}; // 开始输出PWM信号 hi_pwm_start(HI_PWM_PORT_PWM0, 20 * 1000, 40 * 1000); // 停止输出PWM信号 hi_pwm_stop(HI_PWM_PORT_PWM0); // 让三色灯循环亮灭16轮 for (int i = 0; i < 16; i++) { // 每一轮按顺序亮灭三色灯 for (unsigned int j = 0; j < 3; j++) { // 点亮 IoTGpioSetOutputVal(pins[j], IOT_GPIO_VALUE1); // 等待200ms usleep(200 * 1000); // 熄灭 IoTGpioSetOutputVal(pins[j], IOT_GPIO_VALUE0); // 等待100ms usleep(100 * 1000); } } // 工作循环 while (1) { // 设置每个灯的点亮或熄灭状态 for (unsigned int j = 0; j < 3; j++) { IoTGpioSetOutputVal(pins[j], g_ledStates[j]); } // 等待100ms usleep(100 * 1000); } return NULL; } // 按钮(GPIO-08)的中断处理函数 static void OnButtonPressed(char *arg) { (void)arg; // 设置三色LED灯的状态 for (int i = 0; i < 3; i++) { // 根据g_currentBright设置当前点亮的灯 if (i == g_currentBright) { g_ledStates[i] = 1; } // 其他灯熄灭 else { g_ledStates[i] = 0; } } // 实现按键切灯 g_currentBright++; // 循环点亮三色LED灯 if (g_currentBright == 3) g_currentBright = 0; } // 入口函数 static void StartTrafficLightTask(void) { // 定义线程属性 osThreadAttr_t attr; attr.name = "TrafficLightTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 1024; attr.priority = osPriorityNormal; // 初始化GPIO模块 IoTGpioInit(RED_GPIO); // 红色LED灯 IoTGpioInit(GREEN_GPIO); // 绿色LED灯 IoTGpioInit(YELLOW_GPIO); // 黄色LED灯 IoTGpioInit(BUTTON_GPIO); // 按钮 // 设置GPIO-10的功能为GPIO hi_io_set_func(RED_GPIO, HI_IO_FUNC_GPIO_10_GPIO); // 设置GPIO-10的模式为输出模式(引脚方向为输出) IoTGpioSetDir(RED_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-11的功能为GPIO hi_io_set_func(GREEN_GPIO, HI_IO_FUNC_GPIO_11_GPIO); // 设置GPIO-11的模式为输出模式(引脚方向为输出) IoTGpioSetDir(GREEN_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-12的功能为GPIO hi_io_set_func(YELLOW_GPIO, HI_IO_FUNC_GPIO_12_GPIO); // 设置GPIO-12的模式为输出模式(引脚方向为输出) IoTGpioSetDir(YELLOW_GPIO, IOT_GPIO_DIR_OUT); // 设置GPIO-08的功能为GPIO hi_io_set_func(BUTTON_GPIO, HI_IO_FUNC_GPIO_8_GPIO); // 设置GPIO-08的模式为输入模式(引脚方向为输入) IoTGpioSetDir(BUTTON_GPIO, IOT_GPIO_DIR_IN); // 设置GPIO-08的模式为上拉模式(引脚上拉) hi_io_set_pull(BUTTON_GPIO, HI_IO_PULL_UP); // 注册GPIO-08中断处理函数 IoTGpioRegisterIsrFunc(BUTTON_GPIO, //GPIO-08引脚 IOT_INT_TYPE_EDGE, //边沿触发 IOT_GPIO_EDGE_FALL_LEVEL_LOW, //下降沿触发 OnButtonPressed, //中断处理函数 NULL); //中断处理函数的参数 // 设置GPIO-09的功能为PWM0输出 hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT); // 设置GPIO-09的模式为输出模式(引脚方向为输出) IoTGpioSetDir(HI_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT); // 初始化PWM模块 IoTPwmInit(HI_PWM_PORT_PWM0); // 创建线程 if (osThreadNew((osThreadFunc_t)TrafficLightTask, NULL, &attr) == NULL) { printf("Falied to create TrafficLightTask!\n"); } } // 运行入口函数 APP_FEATURE_INIT(StartTrafficLightTask); \applications\sample\wifi-iot\app\pwm_demo\BUILD.gn: # 静态库 static_library("pwm_demo") { sources = [ # "pwm_buz.c" # "pwm_music.c" # "pwm_volume.c" # "traffic_light.c" # "pwm_led.c" "music2.c","traffic_light.c","display.c","oled_ssd1306.c" ] include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", "//base/iot_hardware/interfaces/kits/wifiiot_lite", "//foundation/communication/wifi_lite/interfaces/wifiservice", "//device/hisilicon/hispark_pegasus/sdk_liteos/include", "//device/hisilicon/hispark_pegasus/sdk_liteos/platform/include", "//base/iot_hardware/peripheral/interfaces/kits", "//applications/sample/wifi-iot/app/ssd1306_3rd_driver/ssd1306", ] } \applications\sample\wifi-iot\app\BUILD.gn: import("//build/lite/config/component/lite_component.gni") lite_component("app") { features = [ "pwm_demo", ] } 现在我要加入两首曲子并且实现切歌功能,请为我提供一份可行的代码方案,并告诉我如何添加或修改哪个路径下的哪个文件的详细步骤。
06-13
Break instruction exception - code 80000003 (first chance) 0033:00007ff7`ca9816a3 cc int 3 kd> g Hook system initialized Hooking SendMessageW at address: 0x00007FFB8F95D5B0 Hook set successfully Test window created Sending test message… 没有输出"Message hooked at: …"(其中…是消息参数的地址)。#include <Windows.h> #include <vector> #include <string> #include <intrin.h> #include <mutex> // 回调函数类型定义 typedef bool (*HOOKBACK2)(PCONTEXT); // 硬件断点结构 struct DbgPoint { LPVOID Address; HOOKBACK2 DestCall; LPVOID AddressRet; }; // 硬件断点管理器 class DbgPointManager { private: std::vector<DbgPoint> points; std::mutex mtx; // 线程安全锁 public: // 添加硬件断点 bool AddHookPoint(LPVOID Address, HOOKBACK2 hookBack, LPVOID AddressRet = nullptr) { std::lock_guard<std::mutex> lock(mtx); if (points.size() >= 4) return false; // DR0-DR3只有4个 points.push_back({ Address, hookBack, AddressRet }); return true; } // 查找断点 DbgPoint* FindPoint(LPVOID Address) { std::lock_guard<std::mutex> lock(mtx); for (auto& point : points) { if (point.Address == Address) return &point; } return nullptr; } // 启用硬件断点 void OpenDbg(PCONTEXT context) { std::lock_guard<std::mutex> lock(mtx); context->Dr0 = 0; context->Dr1 = 0; context->Dr2 = 0; context->Dr3 = 0; if (points.size() > 0) context->Dr0 = (ULONG_PTR)points[0].Address; if (points.size() > 1) context->Dr1 = (ULONG_PTR)points[1].Address; if (points.size() > 2) context->Dr2 = (ULONG_PTR)points[2].Address; if (points.size() > 3) context->Dr3 = (ULONG_PTR)points[3].Address; // 设置断点类型:执行断点 (00 = 执行, 01 = 写, 10 = IO, 11 = 读写) context->Dr7 = 0; if (points.size() > 0) context->Dr7 |= (1 << 0); // L0 if (points.size() > 1) context->Dr7 |= (1 << 2); // L1 if (points.size() > 2) context->Dr7 |= (1 << 4); // L2 if (points.size() > 3) context->Dr7 |= (1 << 6); // L3 } }; // Hook管理器 class htdHook2 { private: static htdHook2* instance; DbgPointManager DbgPoints; PVOID handler; bool initialized = false; // 触发初始化函数(使用编译器内部函数替代内联汇编) static void ThreadTrap() { // 使用编译器内部函数替代内联汇编 __nop(); __nop(); __nop(); } public: // 单例模式 static htdHook2* getInstance() { if (!instance) { instance = new htdHook2(); } return instance; } htdHook2() { handler = AddVectoredExceptionHandler(1, VectoredHandler); } ~htdHook2() { if (handler) RemoveVectoredExceptionHandler(handler); instance = nullptr; } // 设置硬件断点Hook bool SetHook(LPVOID Address, HOOKBACK2 hookBack, LPVOID AddressRet = nullptr) { return DbgPoints.AddHookPoint(Address, hookBack, AddressRet); } // VEH异常处理 static LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) { PCONTEXT ctx = ExceptionInfo->ContextRecord; DWORD exceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode; auto manager = getInstance(); // 获取指令指针(兼容32/64位) ULONG_PTR eip = 0; #if defined(_M_X64) eip = ctx->Rip; #else eip = ctx->Eip; #endif char debugMsg[256]; if (exceptionCode == STATUS_BREAKPOINT) { // 0x80000003 sprintf_s(debugMsg, "Breakpoint at: 0x%p\n", (void*)eip); OutputDebugStringA(debugMsg); // 检查是否是我们设置的断点 if (eip == (ULONG_PTR)ThreadTrap) { // 恢复原始代码 DWORD oldProtect; VirtualProtect((LPVOID)ThreadTrap, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *(BYTE*)ThreadTrap = 0x90; // NOP VirtualProtect((LPVOID)ThreadTrap, 1, oldProtect, &oldProtect); // 设置硬件断点 manager->DbgPoints.OpenDbg(ctx); // 确保从下一条指令继续执行 eip++; #if defined(_M_X64) ctx->Rip = eip; #else ctx->Eip = eip; #endif return EXCEPTION_CONTINUE_EXECUTION; } } else if (exceptionCode == STATUS_SINGLE_STEP) { // 0x80000004 sprintf_s(debugMsg, "Single step at: 0x%p\n", (void*)eip); OutputDebugStringA(debugMsg); if (auto point = manager->DbgPoints.FindPoint((LPVOID)eip)) { if (point->DestCall(ctx)) { // 继续单步模式 ctx->Dr7 = 0; ctx->EFlags |= 0x100; // 设置TF标志 } else { // 清除单步标志 ctx->EFlags &= ~0x100; } return EXCEPTION_CONTINUE_EXECUTION; } // 重新激活所有断点 manager->DbgPoints.OpenDbg(ctx); // 清除单步标志 ctx->EFlags &= ~0x100; return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; } // 初始化硬件断点环境 void Init() { if (initialized) return; // 设置临时断点获取CONTEXT DWORD oldProtect; VirtualProtect((LPVOID)ThreadTrap, 1, PAGE_EXECUTE_READWRITE, &oldProtect); BYTE originalByte = *(BYTE*)ThreadTrap; // 保存原始字节 *(BYTE*)ThreadTrap = 0xCC; // INT3 // 触发异常 __debugbreak(); // 恢复原始代码 *(BYTE*)ThreadTrap = originalByte; VirtualProtect((LPVOID)ThreadTrap, 1, oldProtect, &oldProtect); initialized = true; } }; // 初始化静态成员 htdHook2* htdHook2::instance = nullptr; // 示例:消息Hook回调函数(兼容32/64位) bool __stdcall HookMsgCallback(PCONTEXT ctx) { // 获取消息内容(兼容不同架构) DWORD_PTR msgAddr = 0; #if defined(_M_X64) // x64调用约定:第一个参数在RCX msgAddr = ctx->Rcx; #else // x86调用约定:第一个参数在[ESP+4] // 使用安全的指针访问替代内联汇编 DWORD espValue = ctx->Esp; if (espValue) { msgAddr = *(DWORD*)(espValue + 4); } #endif // 在实际应用中解析消息结构 char buf[256]; sprintf_s(buf, "Message hooked at: 0x%p\n", (void*)msgAddr); OutputDebugStringA(buf); return true; // 继续Hook } int main() { OutputDebugStringA("Application started\n"); // 初始化Hook系统 auto hookMgr = htdHook2::getInstance(); hookMgr->Init(); OutputDebugStringA("Hook system initialized\n"); // 设置Hook HMODULE hUser32 = LoadLibraryA("user32.dll"); if (!hUser32) { OutputDebugStringA("Failed to load user32.dll\n"); return 1; } LPVOID targetFunc = GetProcAddress(hUser32, "SendMessageW"); if (!targetFunc) { char errMsg[256]; sprintf_s(errMsg, "Failed to find SendMessageW: error %d\n", GetLastError()); OutputDebugStringA(errMsg); return 1; } char infoMsg[256]; sprintf_s(infoMsg, "Hooking SendMessageW at address: 0x%p\n", targetFunc); OutputDebugStringA(infoMsg); if (!hookMgr->SetHook(targetFunc, HookMsgCallback)) { OutputDebugStringA("Failed to set hook (hardware breakpoint limit reached?)\n"); } else { OutputDebugStringA("Hook set successfully\n"); } // 创建测试窗口 WNDCLASSA wc = { 0 }; wc.lpfnWndProc = DefWindowProcA; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = "TestWindowClass"; if (!RegisterClassA(&wc)) { OutputDebugStringA("Failed to register window class\n"); return 1; } HWND hWnd = CreateWindowA("TestWindowClass", "Hardware Breakpoint Demo", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, GetModuleHandle(NULL), NULL); if (hWnd) { ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); OutputDebugStringA("Test window created\n"); } else { OutputDebugStringA("Failed to create window\n"); return 1; } // 发送测试消息 if (hWnd) { OutputDebugStringA("Sending test message...\n"); SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"Hello, Hardware Breakpoint!"); // 额外发送消息确保触发 SendMessageA(hWnd, WM_PAINT, 0, 0); SendMessageA(hWnd, WM_NCPAINT, 1, 0); } // 主消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } OutputDebugStringA("Application exiting\n"); return 0; }
最新发布
07-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值