最便宜的酒店网站建设手机在线销售网站 - 百度

张小明 2026/1/11 9:13:06
最便宜的酒店网站建设,手机在线销售网站 - 百度,北京建网站,拍摄公司宣传片报价编译器#xff1a;GCC传统的启动文件使用汇编语言实现#xff0c;可读性很低#xff0c;现在分析其内容#xff0c;使用C语言重新实现一遍。完整的代码首先附上成品#xff0c;使用C11标准#xff1a;项目地址 #xff1a;Gitee仓库#include stddef.h#include GCC传统的启动文件使用汇编语言实现可读性很低现在分析其内容使用C语言重新实现一遍。完整的代码首先附上成品使用C11标准项目地址 Gitee仓库#include stddef.h#include stdint.h/*** brief startup.c for stm32f103c8t6* syntax unified* cpu cortex-m3* fpu softvfp* thumb*//* Highest address of the user mode stack */extern uint8_t _estack[];/* defined in linker script */extern uint8_t _sidata[]; /* start address for the initialization values of the .data section.*//* start address for the .data section. defined in linker script */extern uint8_t _sdata[];/* end address for the .data section. defined in linker script */extern uint8_t _edata[];/* start address for the .bss section. defined in linker script */extern uint8_t _sbss[];/* end address for the .bss section. defined in linker script */extern uint8_t _ebss[];const uint32_t BootRAM 0xF108F85F;typedef void (*interruptHandlerType)(void); // use typedef to define the type of interruptHandlerTypeconst interruptHandlerType g_pfnVectors[]; // declare the interrupt vector tablevoid Default_Handler(void); // declare the default interrupt handlervoid Reset_Handler(void) __attribute__((noreturn)); // declare the reset handler/********************************************************************************* Provide weak aliases for each Exception handler to the Default_Handler.* As they are weak aliases, any function with the same name will override* this definition.********************************************************************************/#define WEAK_ALIAS __attribute__((weak, alias(Default_Handler)))WEAK_ALIAS void NMI_Handler(void);WEAK_ALIAS void HardFault_Handler(void);WEAK_ALIAS void MemManage_Handler(void);WEAK_ALIAS void BusFault_Handler(void);WEAK_ALIAS void UsageFault_Handler(void);WEAK_ALIAS void SVC_Handler(void);WEAK_ALIAS void DebugMon_Handler(void);WEAK_ALIAS void PendSV_Handler(void);WEAK_ALIAS void SysTick_Handler(void);WEAK_ALIAS void WWDG_IRQHandler(void);WEAK_ALIAS void PVD_IRQHandler(void);WEAK_ALIAS void TAMPER_IRQHandler(void);WEAK_ALIAS void RTC_IRQHandler(void);WEAK_ALIAS void FLASH_IRQHandler(void);WEAK_ALIAS void RCC_IRQHandler(void);WEAK_ALIAS void EXTI0_IRQHandler(void);WEAK_ALIAS void EXTI1_IRQHandler(void);WEAK_ALIAS void EXTI2_IRQHandler(void);WEAK_ALIAS void EXTI3_IRQHandler(void);WEAK_ALIAS void EXTI4_IRQHandler(void);WEAK_ALIAS void DMA1_Channel1_IRQHandler(void);WEAK_ALIAS void DMA1_Channel2_IRQHandler(void);WEAK_ALIAS void DMA1_Channel3_IRQHandler(void);WEAK_ALIAS void DMA1_Channel4_IRQHandler(void);WEAK_ALIAS void DMA1_Channel5_IRQHandler(void);WEAK_ALIAS void DMA1_Channel6_IRQHandler(void);WEAK_ALIAS void DMA1_Channel7_IRQHandler(void);WEAK_ALIAS void ADC1_2_IRQHandler(void);WEAK_ALIAS void USB_HP_CAN1_TX_IRQHandler(void);WEAK_ALIAS void USB_LP_CAN1_RX0_IRQHandler(void);WEAK_ALIAS void CAN1_RX1_IRQHandler(void);WEAK_ALIAS void CAN1_SCE_IRQHandler(void);WEAK_ALIAS void EXTI9_5_IRQHandler(void);WEAK_ALIAS void TIM1_BRK_IRQHandler(void);WEAK_ALIAS void TIM1_UP_IRQHandler(void);WEAK_ALIAS void TIM1_TRG_COM_IRQHandler(void);WEAK_ALIAS void TIM1_CC_IRQHandler(void);WEAK_ALIAS void TIM2_IRQHandler(void);WEAK_ALIAS void TIM3_IRQHandler(void);WEAK_ALIAS void TIM4_IRQHandler(void);WEAK_ALIAS void I2C1_EV_IRQHandler(void);WEAK_ALIAS void I2C1_ER_IRQHandler(void);WEAK_ALIAS void I2C2_EV_IRQHandler(void);WEAK_ALIAS void I2C2_ER_IRQHandler(void);WEAK_ALIAS void SPI1_IRQHandler(void);WEAK_ALIAS void SPI2_IRQHandler(void);WEAK_ALIAS void USART1_IRQHandler(void);WEAK_ALIAS void USART2_IRQHandler(void);WEAK_ALIAS void USART3_IRQHandler(void);WEAK_ALIAS void EXTI15_10_IRQHandler(void);WEAK_ALIAS void RTCAlarm_IRQHandler(void);WEAK_ALIAS void USBWakeUp_IRQHandler(void);/******************************************************************************** The minimal vector table for a Cortex M3. Note that the proper constructs* must be placed on this to ensure that it ends up at physical address* 0x0000.0000.*******************************************************************************/__attribute__((section(.isr_vector), used))const interruptHandlerType g_pfnVectors[] {(void *)_estack,Reset_Handler,NMI_Handler,HardFault_Handler,MemManage_Handler,BusFault_Handler,UsageFault_Handler,NULL, NULL, NULL, NULL,SVC_Handler,DebugMon_Handler,NULL,PendSV_Handler,SysTick_Handler,WWDG_IRQHandler,PVD_IRQHandler,TAMPER_IRQHandler,RTC_IRQHandler,FLASH_IRQHandler,RCC_IRQHandler,EXTI0_IRQHandler,EXTI1_IRQHandler,EXTI2_IRQHandler,EXTI3_IRQHandler,EXTI4_IRQHandler,DMA1_Channel1_IRQHandler,DMA1_Channel2_IRQHandler,DMA1_Channel3_IRQHandler,DMA1_Channel4_IRQHandler,DMA1_Channel5_IRQHandler,DMA1_Channel6_IRQHandler,DMA1_Channel7_IRQHandler,ADC1_2_IRQHandler,USB_HP_CAN1_TX_IRQHandler,USB_LP_CAN1_RX0_IRQHandler,CAN1_RX1_IRQHandler,CAN1_SCE_IRQHandler,EXTI9_5_IRQHandler,TIM1_BRK_IRQHandler,TIM1_UP_IRQHandler,TIM1_TRG_COM_IRQHandler,TIM1_CC_IRQHandler,TIM2_IRQHandler,TIM3_IRQHandler,TIM4_IRQHandler,I2C1_EV_IRQHandler,I2C1_ER_IRQHandler,I2C2_EV_IRQHandler,I2C2_ER_IRQHandler,SPI1_IRQHandler,SPI2_IRQHandler,USART1_IRQHandler,USART2_IRQHandler,USART3_IRQHandler,EXTI15_10_IRQHandler,RTCAlarm_IRQHandler,USBWakeUp_IRQHandler,NULL, NULL, NULL, NULL, NULL, NULL, NULL,(void *)BootRAM /* 0x108. This is for boot in RAM mode for STM32F10x Medium Density devices. */};/*** brief This is the code that gets called when the processor receives an* unexpected interrupt. This simply enters an infinite loop, preserving* the system state for examination by a debugger.** param None* retval : None*/void Default_Handler(void){while (1) {/* Infinite loop */}}/*** brief data sector initialization function**/static void CopyDataInit(void){const uint32_t *src (void *)_sidata;const uint32_t *data_end (void *)_edata;for (uint32_t *p (void *)_sdata; p data_end; p, src) {*p *src;}}/*** brief bss sector zero initialization function**//* BSS zero initialization function */static void FillZerobss(void){const uint32_t *bss_end (void *)_ebss;for (uint32_t *p (void *)_sbss; p bss_end; p) {*p 0x00;}}/*** brief This is the code that gets called when the processor first* starts execution following a reset event. Only the absolutely* necessary set is performed, after which the application* supplied main() routine is called.* param None* retval : None*/// the function will never returnvoid Reset_Handler(void){extern void SystemInit(void); // defined in system_stm32f1xx.cextern int main(void); // defined in main.cextern void __libc_init_array(void); // defined in newlib/* Call the clock system initialization function */SystemInit();/* Initialize data and bss sections */CopyDataInit();FillZerobss();/* Call static constructors */__libc_init_array();/* Call the applications entry point */main();/* Should never reach here */while (1) {/* Infinite loop */}}程序分析链接器脚本分析以STM32CubeMX生成使用的CMake工具链的stm32f103c8t6的项目为例有一个启动文件 startup_stm32f103xb.s 和链接器脚本 STM32F103XX_FLASH.ld启动文件中定义的内容是上电以后执行的第一件事情而链接器脚本指定程序的链接方式和内存区域分配方式。首先分析链接器脚本文件进行逐段分析/* Entry Point */ENTRY(Reset_Handler)定义了入口函数也即上电之后执行的第一个函数此处为 Reset_Handler。/* Specify the memory areas */MEMORY{RAM (xrw) : ORIGIN 0x20000000, LENGTH 20KFLASH (rx) : ORIGIN 0x8000000, LENGTH 64K}定义了内存区域分别为RAM 区域可执行x、可读r、可写w的区域大小为 20K起始地址为 0x20000000。FLASH 区域可读r、可执行x大小为 64K起始地址为 0x8000000。/* Highest address of the user mode stack */_estack ORIGIN(RAM) LENGTH(RAM); /* end of RAM */定义程序栈起始地址 _estack由于栈是从高地址向低地址延伸所以起始地址定义为 RAM 区域的结束位置。/* Generate a link error if heap and stack dont fit into RAM */_Min_Heap_Size 0x0; /* required amount of heap */_Min_Stack_Size 0x400; /* required amount of stack */定义堆和栈的大小。如果需要使用 malloc 等动态内存分配则分配的内存就位于堆中。此处不用因此设为0。然后是段定义/* Define output sections */SECTIONS{/*...... */}分为几个段/* The startup code goes first into FLASH */.isr_vector :{. ALIGN(4);KEEP(*(.isr_vector)) /* Startup code */. ALIGN(4);} FLASH为中断向量表所在的地址/* Constant data goes into FLASH */.rodata :{. ALIGN(4);*(.rodata) /* .rodata sections (constants, strings, etc.) */*(.rodata*) /* .rodata* sections (constants, strings, etc.) */. ALIGN(4);} FLASH定义const 变量存放在 Flash 中。接下来的 .ARM.extab、.ARM、.preinit_array、.init_array、.fini_array 与C有关略过。接着是/* used by the startup to initialize data */_sidata LOADADDR(.data);定义符号 _sidata用于指定 .data 段在Flash中的起始地址这样就可以在C代码文件中使用这个“变量”/* Initialized data sections goes into RAM, load LMA copy after code */.data :{. ALIGN(4);_sdata .; /* create a global symbol at data start */*(.data) /* .data sections */*(.data*) /* .data* sections */*(.RamFunc) /* .RamFunc sections */*(.RamFunc*) /* .RamFunc* sections */. ALIGN(4);} RAM AT FLASH此处定义了 .data 段用于存放已经初始化过的全局变量这些变量的值会存放在Flash中在程序运行时在启动文件中将其复制到RAM中的对应位置。.bss (NOLOAD) : ALIGN(4){*(.bss)*(.bss*)*(COMMON). ALIGN(4);_ebss .; /* define a global symbol at bss end */__bss_end__ _ebss;PROVIDE( __bss_end .);} RAM定义了 .bss 段用于存放未初始化的全局变量这些变量的值在程序运行时会被初始化为0。/* User_heap_stack section, used to check that there is enough RAM left */._user_heap_stack (NOLOAD) :{. ALIGN(8);PROVIDE ( end . );PROVIDE ( _end . );. . _Min_Heap_Size;. . _Min_Stack_Size;. ALIGN(8);} RAM定义了一个 .user_heap_stack 段用于堆栈的分配保存在RAM中。/* Remove information from the standard libraries *//DISCARD/ :{libc.a:* ( * )libm.a:* ( * )libgcc.a:* ( * )}移除 libc.a、libm.a、libgcc.a 等标准库符号减小程序体积。启动文件分析并重写接着分析启动并重写文件首先是.syntax unified.cpu cortex-m3.fpu softvfp.thumb定义了cpu、fpu、指令集等内容略过。然后.global g_pfnVectors.global Default_Handler相当于C语言中声明了两个全局变量。第一个是中断向量组第二个是默认的中断处理函数。中断向量组中是紧凑排列的各种中断函数的入口地址我们知道所有的中断函数都是 void handler(void) 类型因此它等价为一个函数指针数组为了防止不小心修改可以添加 const 限定符typedef void (*interruptHandlerType)(void); // 中断函数指针类型const interruptHandlerType g_pfnVectors[]; // 声明中断向量表然后是/* start address for the initialization values of the .data section.defined in linker script */.word _sidata/* start address for the .data section. defined in linker script */.word _sdata/* end address for the .data section. defined in linker script */.word _edata/* start address for the .bss section. defined in linker script */.word _sbss/* end address for the .bss section. defined in linker script */.word _ebss.equ BootRAM, 0xF108F85F声明了几个 .word 类型的变量相当于C语言中的 uint32_t 类型这些符号定义在链接器脚本中用于指定各个数据段的起始、终止地址。最后的 .equ BootRAM, 0xF108F85F 定义了从RAM中启动的地址需要加在中断向量组的最后。因此在C语言中我们可以定义extern uint32_t _sdata;// ***const uint32_t BootRAM 0xF108F85F;使用时需要进行取地址操作得到 data 段的起始地址。但实际上我们并不关心变量的“类型”只需要知道链接脚本中定义的“符号”表示这个“变量”保存在这个位置也即“变量的地址”是“data”段的起始地址。因此直接将其定义为 uint8_t[] 类型extern uint8_t _sdata[];这样便省去了去地址的操作。接着是 Reset_Handler 函数的定义它是上电之后第一个执行的函数。下面是它的声明.section .text.Reset_Handler // 定义代码段.weak Reset_Handlel // 定义为弱符号.type Reset_Handler, %function // 定义为函数类型这一部分可以改写为C代码__attribute__((weak))void Reset_Handler(void);然后是函数体Reset_Handler:bl SystemInit // 调用 SystemInit 函数// 从 Flash 中复制数据到 data 段// 清零 bss 段bl __libc_init_array // 调用 C 静态构造函数bl main // 调用 main 函数进入主程序bx lr // 相当于 main 函数中的 return可以改写为C代码void data_init(void);void bss_init(void);__attribute__((noreturn))void Reset_Handler(void){SystemInit(); // 调用 SystemInit 函数data_init(); // 复制数据到data段bss_init(); // 清零bss段__libc_init_array(); // 调用C静态构造函数main(); // 进入主程序while (true);}其中 data_init 和 bss_init 是我们自己定义的两个函数用于初始化 .data 和 .bss 段其汇编代码如下注释部分为C风格伪代码/* Copy the data segment initializers from flash to SRAM */ldr r0, _sdata // r0 _sdata;ldr r1, _edata // r1 _edata;ldr r2, _sidata // r2 _sidata;movs r3, #0 // r3 0;b LoopCopyDataInit // goto LoopCopyDataInit;CopyDataInit: // CopyDataInit:ldr r4, [r2, r3] // r4 *(uint32_t*)(r2 r3);str r4, [r0, r3] // *(uint32_t*)(r0 r2) r4;// // 两句合起来等价于// // *(uint32_t*)(r0 r2) *(uint32_t*)(r2 r2);adds r3, r3, #4 // r3 4;LoopCopyDataInit: // LoopCopyDataInit:adds r4, r0, r3 // r4 r0 r3;cmp r4, r1 // cmp res(r4,r1); // 假设有个enum cmp用于存储两个数字比较情况bcc CopyDataInit // if(cmp less){ goto CopyDataInit; }/* Zero fill the bss segment. */ldr r2, _sbssldr r4, _ebssmovs r3, #0b LoopFillZerobssFillZerobss:str r3, [r2]adds r2, r2, #4LoopFillZerobss:cmp r2, r4bcc FillZerobss可以看到本质上就是把 flash 中的数据拷贝到 ram 中拷贝的长度为 _edata - _sdata源地址为 flash 中的 _sidata目的地址为 ram 中的 _sdata。清零部分同理只不过是把拷贝改为设置为0。需要注意为了增加处理效率一次复制 4 字节使用 uint32_t* 类型指针来操作。因此其逻辑改写为C代码如下extern uint8_t _sdata[];extern uint8_t _edata[];extern uint8_t _sidata[];uint32_t *data_start _sdata; // data段的起始地址uint32_t *data_end _edata; // data段的结束地址uint32_t *source_addr _sidata; // flash中data的数据的起始地址uint32_t offset 0;// 以 word 为单位也即4字节为单位从 flash 中拷贝数据到 ram 中while (offset data_end) {uint32_t *src (void*)_sidata offset;uint32_t *dst (void*)_sdata offset;*dst *src; // 从 Flash 中拷贝数据到 RAM 中offset 4; // 指针偏移4字节也即一个 word 的长度}// 清零部分略可以借助C库函数 memcpy 和 memset 来实现 data_init 和 bss_init 函数肯定比逐个复制更高效但是会多占大约 400Byte 的 Flash 空间因此此处仅作示例实际使用中最好还是逐字复制。/* Data copy function */static void data_init(void){size_t data_size _edata - _sdata; // get data sizememcpy(_sdata, _sidata, data_size); // copy data from flash to ram}/* BSS zero initialization function */static void bss_init(void){size_t bss_size _ebss - _sbss; // get bss sizememset(_sbss, 0x00, bss_size); // clear bss section}然后是 Default_Handler 函数/*** brief This is the code that gets called when the processor receives an* unexpected interrupt. This simply enters an infinite loop, preserving* the system state for examination by a debugger.** param None* retval : None*/.section .text.Default_Handler,ax,%progbitsDefault_Handler:Infinite_Loop:b Infinite_Loop // goto Infinite_Loop;.size Default_Handler, .-Default_Handler它是中断处理函数的默认实现当发生未知中断时它会进入一个无限循环保持系统状态等待调试器来查看。易知它是个死循环因此可以改写为C代码void Default_Handler(void){while(1){}}最后是中断向量组定义/******************************************************************************** The minimal vector table for a Cortex M3. Note that the proper constructs* must be placed on this to ensure that it ends up at physical address* 0x0000.0000.*******************************************************************************/.section .isr_vector,a,%progbits.type g_pfnVectors, %object.size g_pfnVectors, .-g_pfnVectorsg_pfnVectors:.word _estack.word Reset_Handler// .......word BootRAM /* 0x108. This is for boot in RAM mode forSTM32F10x Medium Density devices. */以及其弱符号定义.weak NMI_Handler.thumb_set NMI_Handler,Default_Handler.weak HardFault_Handler.thumb_set HardFault_Handler,Default_Handler.weak MemManage_Handler.thumb_set MemManage_Handler,Default_Handler// ......改写为C代码// 函数声明__attribute__((weak, alias(Default_Handler))) func(void) NMI_Handler;__attribute__((weak, alias(Default_Handler))) func(void) HardFault_Handler;// ......__attribute__((weak, alias(Default_Handler))) func(void) USBWakeUp_IRQHandler;// 向量组定义__attribute__((section(.isr_vector)))const (*const f_pfnVectors[]) {(void(*)void)_estack,Reset_Handler,// ...///(void(*)void)BootRAM};
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

珠海婚恋网站建设市场分析wordpress页面获取最新文章

系统程序文件列表项目功能:区域信息,居民,工作人员,在线举报,体温登记,区域疫情,访客申请,外出申请,进入申请,居家隔离,住宅分配,公告信息开题报告内容一、研究背景与意义1.1 研究背景自2019年底新型冠状病毒(COVID-19)爆发以来,全…

张小明 2026/1/3 8:19:55 网站建设

济南小程序网站开发互联网+创新创业项目计划书案例

FaceFusion后处理模块亮点:色彩匹配与边缘融合的艺术 在数字内容创作日益普及的今天,人脸替换技术早已不再是简单的“换脸”玩具。从短视频平台上的趣味滤镜,到影视工业中的高保真替身合成,用户对视觉真实感的要求正以前所未有的速…

张小明 2026/1/6 20:16:51 网站建设

长沙外贸网站建设网页图片文字识别

硅谷增长女神掀桌子:这10个“增长神话”,其实全是坑!大家好,我是01。 最近我在听 Lenny’s Podcast 的时候,听到了一期让我直呼“好家伙”的内容。嘉宾是 Elena Verna,前 Amplitude、Miro、Dropbox 的增长负…

张小明 2025/12/30 23:57:41 网站建设

常州网站搭建网页布局怎么设计

人工智能面临的一个重大问题是计算机内存与处理能力之间的交互。当算法运行时,数据在这两个组件之间快速流动。然而,AI模型依赖大量数据,这会产生瓶颈。普渡大学和佐治亚理工学院周一在《科学前沿》期刊发表的一项新研究,提出了一…

张小明 2025/12/26 2:59:29 网站建设

宁波网站seo报价聊城公司网站建设

流程工厂数字孪生的商业案例剖析 服务解决方案的关键要素 在提供流程工厂数字孪生服务解决方案时,有几个关键要素起着决定性作用。首先是人员角色,主要包括 AI 开发者、数据科学家、产品所有者和产品经理。 - AI 开发者 :负责算法的实施、优化和 AI 的训练。准确的数据…

张小明 2025/12/31 6:55:11 网站建设

建设本地网站陕麻圈辅助软件

当车规级定位导航技术跨越赛道,赋能工业与公共服务场景,将碰撞出怎样的创新火花? 2025年12月17日,全国首届聚焦无人设备智能巡检的“共建 AI 治理新生态,共赢智慧巡检大未来”——诚芯智联行业渠道合作峰会在武汉光谷圆…

张小明 2025/12/26 4:46:50 网站建设