当前位置: 首页 > news >正文

嵌入式IDE(2):KEIL中SCF分散加载链接文件详解和实例分析

在上一篇文章IAR中ICF链接文件详解和实例分析中,我通过I.MX RT1170的SDK中的内存映射关系,分析了IAR中的ICF链接文件的语法。对于MCU编程所使用的IDE来说,IAR和Keil用得比较多,所以这一篇文章就来分析一下Keil的分散文件.scf(scatter file)。

文章目录

  • 1 内存映射
  • 2 SCF语法分析
    • 2.1 工程的SCF文件
    • 2.2 define
    • 2.3 加载区域和执行区域

1 内存映射

和上一篇文章一样,同样使用I.MX RT1170的SDK中的链接文件进行分析,通过实际的分散文件来学习里面的语法。和上一节也是同一个例程,除了芯片自带的RAM外,还有NOR Flash和SDRAM。首先来看一下整个工程的内存映射表格:

类型名称起始地址大小
FlashNOR Flash0x300000000x1000000
RAMSDRAM0x800000000x3000000
RAMNCACHE_REGION0x830000000x1000000
RAMSRAM_DTC_cm70x200000000x40000
RAMSRAM_ITC_cm70x00x40000
RAMSRAM_OC10x202400000x80000
RAMSRAM_OC20x202c00000x80000
RAMSRAM_OC_ECC10x203400000x10000
RAMSRAM_OC_ECC20x203500000x10000

对于我们的工程来说,有以下几个内存:

  1. 两个256KB的紧耦合内存DTCMITCM
  2. 两个带ECC的片内RAM:OC1OC2
  3. 在映射的起始地址为0x30000000的FlexSPI1接口上接了一个16MB的NOR Flash
  4. 在映射的起始地址为0x80000000的FlexSPI2接口上接了一个64MB的SDRAM。其中,前48MB用于可缓存的区域,后16MB(NCACHE_REGION)用于不可缓存区域,通常直接与硬件进行交互的buffer需要设置为不可缓存。

2 SCF语法分析

2.1 工程的SCF文件

针对上面的内存映射,官方的SDK中提供的SCF文件如下:

#if (defined(__ram_vector_table__))#define __ram_vector_table_size__    0x00000400
#else#define __ram_vector_table_size__    0x00000000
#endif#define m_flash_config_start           0x30000400
#define m_flash_config_size            0x00000C00#define m_ivt_start                    0x30001000
#define m_ivt_size                     0x00000020#define m_boot_data_start              0x30001020
#define m_boot_data_size               0x00000010#define m_dcd_data_start               0x30001030
#define m_dcd_data_size                0x000006E8#define m_xmcd_data_start              0x30001040
#define m_xmcd_data_size               0x00000204#define m_interrupts_start             0x30002000
#define m_interrupts_size              0x00000400#define m_text_start                   0x30002400
#if (defined(__use_flash64MB__))
#define m_text_size                    0x03FFDC00
#else
#define m_text_size                    0x00FFDC00
#endif#define m_qacode_start                 0x00000000
#define m_qacode_size                  0x00040000#define m_interrupts_ram_start         0x80000000
#define m_interrupts_ram_size          __ram_vector_table_size__#define  m_data_start                  (m_interrupts_ram_start + m_interrupts_ram_size)
#define  m_data_size                   (0x03000000 - m_interrupts_ram_size)#define m_data2_start                  0x20000000
#define m_data2_size                   0x00040000#define m_data3_start                  0x202C0000
#define m_data3_size                   0x00080000#define m_ncache_start                 0x83000000
#define m_ncache_size                  0x01000000/* Sizes */
#if (defined(__stack_size__))#define Stack_Size                   __stack_size__
#else#define Stack_Size                   0x0400
#endif#if (defined(__heap_size__))#define Heap_Size                    __heap_size__
#else#define Heap_Size                    0x0400
#endif#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
LR_m_text m_flash_config_start m_text_start+m_text_size-m_flash_config_start {   ; load region size_regionRW_m_config_text m_flash_config_start FIXED m_flash_config_size { ; load address = execution address* (.boot_hdr.conf, +FIRST)}RW_m_ivt_text m_ivt_start FIXED m_ivt_size { ; load address = execution address* (.boot_hdr.ivt, +FIRST)}RW_m_boot_data_text m_boot_data_start FIXED m_boot_data_size { ; load address = execution address* (.boot_hdr.boot_data, +FIRST)}#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)RW_m_dcd_data_text m_dcd_data_start FIXED m_dcd_data_size { ; load address = execution address* (.boot_hdr.dcd_data, +FIRST)}
#elif defined(XIP_BOOT_HEADER_XMCD_ENABLE) && (XIP_BOOT_HEADER_XMCD_ENABLE == 1)RW_m_xmcd_data_text m_xmcd_data_start FIXED m_xmcd_data_size { ; load address = execution address* (.boot_hdr.xmcd_data, +FIRST)}
#endif
#else
LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start {   ; load region size_region
#endifVECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address* (.isr_vector,+FIRST)}ER_m_text m_text_start FIXED m_text_size { ; load address = execution address* (InRoot$$Sections).ANY (+RO)}
#if (defined(__ram_vector_table__))VECTOR_RAM m_interrupts_ram_start EMPTY m_interrupts_ram_size {}
#elseVECTOR_RAM m_interrupts_start EMPTY 0 {}
#endifRW_m_data2 m_data2_start m_data2_size {* (RamFunction)* (DataQuickAccess)}
#if (defined(__heap_noncacheable__))RW_m_data m_data_start m_data_size-Stack_Size { ; RW data
#elseRW_m_data m_data_start m_data_size-Stack_Size-Heap_Size { ; RW data
#endif.ANY (+RW +ZI)*(*m_usb_dma_init_data)*(*m_usb_dma_noninit_data)}
#if (!defined(__heap_noncacheable__))ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up}
#endifARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down}RW_m_ram_text m_qacode_start m_qacode_size { ;* (CodeQuickAccess)}
#if (defined(__heap_noncacheable__))RW_m_ncache m_ncache_start m_ncache_size - Heap_Size { ; ncache data
#elseRW_m_ncache m_ncache_start m_ncache_size { ; ncache data
#endif* (NonCacheable.init)* (*NonCacheable)}
#if (defined(__heap_noncacheable__))ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up}RW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size { ; Empty region added for MPU configuration
#elseRW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache) { ; Empty region added for MPU configuration
#endif}
}

2.2 define

先来分析第一段分散文件,KEIL的分散文件的语法define#if defined语句与C语言一致,所以下面这一段还是很好理解的:

#if (defined(__ram_vector_table__))#define __ram_vector_table_size__    0x00000400
#else#define __ram_vector_table_size__    0x00000000
#endif#define m_flash_config_start           0x30000400
#define m_flash_config_size            0x00000C00#define m_ivt_start                    0x30001000
#define m_ivt_size                     0x00000020#define m_boot_data_start              0x30001020
#define m_boot_data_size               0x00000010#define m_dcd_data_start               0x30001030
#define m_dcd_data_size                0x000006E8#define m_xmcd_data_start              0x30001040
#define m_xmcd_data_size               0x00000204#define m_interrupts_start             0x30002000
#define m_interrupts_size              0x00000400#define m_text_start                   0x30002400
#if (defined(__use_flash64MB__))
#define m_text_size                    0x03FFDC00
#else
#define m_text_size                    0x00FFDC00
#endif#define m_qacode_start                 0x00000000
#define m_qacode_size                  0x00040000#define m_interrupts_ram_start         0x80000000
#define m_interrupts_ram_size          __ram_vector_table_size__#define  m_data_start                  (m_interrupts_ram_start + m_interrupts_ram_size)
#define  m_data_size                   (0x03000000 - m_interrupts_ram_size)#define m_data2_start                  0x20000000
#define m_data2_size                   0x00040000#define m_data3_start                  0x202C0000
#define m_data3_size                   0x00080000#define m_ncache_start                 0x83000000
#define m_ncache_size                  0x01000000/* Sizes */
#if (defined(__stack_size__))#define Stack_Size                   __stack_size__
#else#define Stack_Size                   0x0400
#endif#if (defined(__heap_size__))#define Heap_Size                    __heap_size__
#else#define Heap_Size                    0x0400
#endif

先说明一下,I.MX系列单片机上电会进入L1 BootLoader,它用来引导程序如何启动,比如说是否加密、加密密钥、是XIP还是non-XIP(就要拷贝到RAM)、是否要初始化时钟。在NOR Flash启动的情况下,程序镜像的前0x2000字节就是用来给L1 BootLoader提供一些启动信息的,这里不必过分关注这些字段的意义,若想详细理解可以参考我的这篇文章I.MX RT1170启动详解:Boot配置、Bootable image头的组成。
(1)__ram_vector_table__没有在别的地方定义,所以__ram_vector_table_size__为0。这也很好理解,因为这里有NOR Flash,向量表就不放到RAM中了,而是放在NOR Flash的最前面。
(2)m_flash_config_startm_flash_config_size:用来给L1 BootLoader提供NOR Flash的配置信息,因为上电后L1 BootLoader用最慢的最保险的配置来初始化NOR Flash,如果用户希望自行配置一些参数,比如时钟变快一些,就可以在这个字段填充配置信息,起始地址为0x30000400(NOR Flash的基地址为0x30000000),长度为0xC00
(3)m_ivt_startm_ivt_size:IVT(Image Vector Table)字段,用来保存程序入口地址等参数
(4)m_boot_data_startm_boot_data_size:用来保存镜像的绝对起始地址和大小
(5)m_dcd_data_startm_dcd_data_sizeDCD字段,一般用来初始化SDRAM,特别是希望程序在SDRAM运行的时候需要配置此字段
(6)m_xmcd_data_startm_xmcd_data_size:可以看到这里的起始地址和大小与上面的DCD字段重合了,实际上二者的功能类似,只不过DCD的配置是一个个寄存器配置的指令,比较复杂,而XMCD简化了这些配置操作,这两个字段是二选一的。
(7)m_interrupts_startm_interrupts_size:前面说了,L1 BootLoader的头信息的大小为0x2000,所以从0x2000开始就是程序的开始,最前面放置向量表,长度为0x400
(8)m_text_startm_text_size:代码段紧接着向量表后面,起始地址为0x30002400,这里__use_flash64MB__为假,我们假设用的是16MB(0x1000000)的NOR Flash,剩下的大小就是0x1000000-0x2400=0x00FFDC00
(9)m_qacode_startm_qacode_size:即前面内存映射中芯片内部的SRAM_ITC_cm7
(10)m_interrupts_ram_startm_interrupts_ram_size:如果向量表没有放在NOR Flash,就放在SDRAM的起始,这里由于放在NOR Flash,这两个字段没有用到
(11)m_data_startm_data_size:data数据段,这里将data段放在了SDRAM。这里SDRAM的大小为64M,这个字段占了前48M。
(12)m_data2_startm_data2_sizem_data3_startm_data3_size:同样是data数据段,分别为SRAM_ITC_cm7SRAM_OC2,即片内的RAM都可以作为data段放置变量

  • SRAM_OC1没有用到,我们可以自行声明。因为L1 BootLoader运行时用到了这块SRAM,所以使用时需要考虑使用这块SRAM的时间。

(13)m_ncache_startm_ncache_size:即SDRAM最后的16M用来做non-cacheable区域,比如GUI绘制的Buffer、摄像头的Buffer和DMA的数据,这种直接与硬件交互的内存,需要定义在不可缓存的区域。这与MPU配置有关,可以参考我的MPU系列的文章MPU内存保护单元详解及例子和L1 Cache之I-Cache和D-cache详解。
(14)Stack_SizeHeap_Size:分别为栈和堆的大小,由于程序中使用了FreeRTOS,所以只要保证这里的栈和堆的大小能够成功初始化FreeRTOS即可,初始化FreeRTOS过程应该没有内存分配,所以Heap Size可以设置为0。

2.3 加载区域和执行区域

接下来开始涉及到一些分散文件的语法,参考文档:<DUI0377G_02_mdk_armlink_user_guide.pdf>(可以在KEIL安装目录下找到)。
相比IAR,KEIL的分散文件的语法简单地多,和Linux的ld文件差不多,分散文件就由一个或多个加载区域(Load Region)构成,如下图所示:
在这里插入图片描述
加载区域的语法如下:

load_region_name (base_address | ("+" offset)) [attribute_list] [max_size]
"{"
execution_region_description+
"}"
  • load_region_name(名称): 用于由链接器识别不同加载区域的独特标签,每个加载区域必须具有唯一的名称
  • base_address(基地址):加载区域内的代码和数据在内存中放置的起始内存地址
  • attribute_list(属性): 定义加载区域的特性和行为,包括只读、读写、仅执行或其他内存保护属性
  • max_size(最大大小): 可选,用于限制加载区域的大小,防止内存溢出
  • execution_region_description(执行区域): 加载区域可以包含一个或多个执行区域。执行区域表示连续的代码和数据块,作为一个单独的单元加载到内存中

如果要把所有语法都总结到文章中就太耗时了,所以还是继续分析分散文件,出现了什么语法或关键字,我们再来去找它的意思。由于后面的分散文件中的宏定义太多而影响阅读,这里假设XIP_BOOT_HEADER_ENABLE=1XIP_BOOT_HEADER_DCD_ENABLE=1XIP_BOOT_HEADER_XMCD_ENABLE=0__heap_noncacheable__(表示将堆放置在non-cacheable区域,保证堆内存不会收到缓存的影响)。

剩下的分散文件实际上就是定义了一个加载区域LR_m_text,它的起始地址为m_flash_config_start(0x30000400),最大的大小为m_text_start+m_text_size-m_flash_config_start(16M-0x400=0xFFFC00),即从0x30000400处开始链接,大小为0xFFFC00,这个大小仅限制加载区域的大小(下面属性为FIXED的执行区域)。0~0x400与NXP RT系列单片机的加密启动有关,这些字段编译器无法进行填充,所以这里就没有考虑。

LR_m_text m_flash_config_start m_text_start+m_text_size-m_flash_config_start {   ; load region size_region......
}
  • 在分散文件中,;后面为注释

在加载区域LR_m_text下有非常多个执行区域,下面来一个个分析一下:

1、RW_m_config_text:起始地址0x30000400,大小0xC00

RW_m_config_text m_flash_config_start FIXED m_flash_config_size { ; load address = execution address* (.boot_hdr.conf, +FIRST)
}
  • FIXED:执行区域的属性,表示让执行区域的执行地址与加载地址尽量保持相等。这意味着,分配给这个执行区域的代码和数据在加载到内存时会尽量放置在指定的执行地址上。如果因为内存冲突或空间不足等原因无法满足,则链接器会报错。
  • +FIRST:表示把该section放在该执行区域的最开始的地方

所以这里就是从0x30000400开始处开始放置boot_hdr.conf段,因为放置的位置必须固定才能被L1 BootLoader正确识别,所以执行区域需要用FIXED属性。

2、RW_m_ivt_text:起始地址0x30001000,大小0x00000020

RW_m_ivt_text m_ivt_start FIXED m_ivt_size { ; load address = execution address* (.boot_hdr.ivt, +FIRST)
}

同上,放置L1 BootLoader的引导头。

3、RW_m_boot_data_text:起始地址0x30001020,大小0x00000010

RW_m_boot_data_text m_boot_data_start FIXED m_boot_data_size { ; load address = execution address* (.boot_hdr.boot_data, +FIRST)
}

同上,放置L1 BootLoader的引导头。

4、RW_m_dcd_data_text:起始地址0x30001030,大小0x000006E8

RW_m_dcd_data_text m_dcd_data_start FIXED m_dcd_data_size { ; load address = execution address* (.boot_hdr.dcd_data, +FIRST)
}

同上,放置L1 BootLoader的引导头。

5、VECTOR_ROM:起始地址0x30002000,大小0x00000400

VECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address* (.isr_vector,+FIRST)
}

放置中断向量表。在启动文件startup_MIMXRT1176_cm7.S文件中定义了该段:.section .isr_vector, "a",这里的a表示将该段标记为可分配(allocatable)的,意味着它在链接时可以被分配到内存中的某个位置。

6、ER_m_text:起始地址0x30002400,大小0x00FFDC00

ER_m_text m_text_start FIXED m_text_size { ; load address = execution address* (InRoot$$Sections).ANY (+RO)
}
  • InRoot$$Sections是在分散文件中使用的特殊标记,用来将压缩数据段放置该执行区域中,以确保这些数据段在运行时能够被自动解压缩并提供给程序使用。该特性是ARM为了减少存储空间占用设计的,上电后ARM库会根据此段来进行解压。
    • 参考文章:Example of placing code in a root region
  • .ANY:可以理解为*,表示所有段,但.ANY可以用在多个执行区域中,而*一般只用在一个执行区域中,所以.ANY会更灵活一些。具体参考手册7.4章节<Placement of unassigned sections with the .ANY module selector>
  • (+RO):只读数据段

这里表示将所有的只读数据段放置在这个执行区域。

7、VECTOR_RAM :这里将中断向量表放置在NOR Flash了,这个执行区域没有用到

VECTOR_RAM m_interrupts_start EMPTY 0 {
}
  • EMPTY表示保留一个空区域,但这里区域的大小设为0,所以这段执行区域没有任何作用

8、RW_m_data2:起始地址0x20000000,大小0x00040000

RW_m_data2 m_data2_start m_data2_size {* (RamFunction)* (DataQuickAccess)
}

这里定义了两个Section:RamFunctionDataQuickAccess,在程序中都可以用__attribute__((section("")))来定义函数或变量到内部的SRAM_DTCM中,可以加快函数的执行速度和数据的访问速度。

9、RW_m_data:起始地址0x80000000,大小0x03000000-0x400

RW_m_data m_data_start m_data_size-Stack_Size { ; RW data.ANY (+RW +ZI)*(*m_usb_dma_init_data)*(*m_usb_dma_noninit_data)
}

这个执行区域就是SDRAM的前48M,将所有的读写数据段和bss段放置在此,同时声明两个usb段,用于SDK中对于USB相关功能的实现。实际上USB段放在non-cacheable区域肯定是可以运行的,但是同时也意味着没有用到缓存,速度就会降低很多。所以就可以将USB相关变量声明到cacheable的区域,然后在代码中必要的地方手动缓存更新相关函数,如SCB_CleanInvalidateDCacheSCB_CleanDCache

10、ARM_LIB_STACK:起始地址0x83000000,大小0x400

ARM_LIB_STACK m_data_start+m_data_size EMPTY -Stack_Size { ; Stack region growing down
}
  • ARM_LIB_STACK:栈的执行区域的固定名称

这里的Stack_Size的前面有一个-,表示栈是向下生长的。

11、RW_m_ram_text:起始地址0x00000000,大小0x00040000

RW_m_ram_text m_qacode_start m_qacode_size { ;* (CodeQuickAccess)
}

与上面的7类似,声明一个CodeQuickAccess段,用于将函数链接到内部的SRAM_ITCM中,因为内部的SRAM的速度比NOR Flash或SDRAM的访问速度都快得多。

12、RW_m_ncache:起始地址0x83000000,大小0x01000000-0x400

RW_m_ncache m_ncache_start m_ncache_size - Heap_Size { ; ncache data* (NonCacheable.init)* (*NonCacheable)
}

定义non-cacheable区域的两个段NonCacheable.initNonCacheable,同时预留堆的空间,因为这里我们假设堆空间也为non-cacheable

13、ARM_LIB_HEAP:大小0x400

ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up
}
  • +0:表示为上一个执行区域的结束地址,根据用户放置到RW_m_ncache执行区域的变量的多少和大小来决定这个地址
  • ARM_LIB_HEAP:堆的执行区域的固定名称

定义堆空间的内存。

14、RW_m_ncache_unused

RW_m_ncache_unused +0 EMPTY m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size { ; Empty region added for MPU configuration
}

同样放置在上一个执行区域的结束地址处,用来给MPU进行配置,大小m_ncache_size-ImageLength(RW_m_ncache)-Heap_Size即除去变量和堆外的剩下的non-cacheable区域。

  • ImageLength可以取某个执行区域占的大小

相关文章:

嵌入式IDE(2):KEIL中SCF分散加载链接文件详解和实例分析

在上一篇文章IAR中ICF链接文件详解和实例分析中&#xff0c;我通过I.MX RT1170的SDK中的内存映射关系&#xff0c;分析了IAR中的ICF链接文件的语法。对于MCU编程所使用的IDE来说&#xff0c;IAR和Keil用得比较多&#xff0c;所以这一篇文章就来分析一下Keil的分散文件.scf(scat…...

Linux防火墙常用操作及端口开放

Linux防火墙常用操作及端口开放 1.查看防火墙状态 firewall-cmd --state 2.开启防火墙 systemctl start firewalld.service 3.开启指定端口 firewall-cmd --zonepublic --add-port3306/tcp --permanent firewall-cmd --zonepublic --add-port6379/tcp --permanent 显示success表…...

[JAVAee]Linux上的javax.mail报错

我们把在window写的项目部署到Linux上的Tomcat时,如果发现使用不了了,该如何找到错误呢?找到报错的地方在哪呢? 在Linux环境下来到Tomcat目录下的logs目录,输入: tail -f catalina.out -n 500 tail 就是把文件的末尾几行读取到终端上,并会持续刷新 -f 循环读取 catalina.ou…...

开学季|校园迎新哪家强?VR全景来导航

九月开学迎新季&#xff0c;各大高校的迎新活动开展的如火如荼&#xff0c;随着科技的不断进步&#xff0c;高校为了更好的开展迎新活动&#xff0c;让新生们尽快熟悉新的校园和生活&#xff0c;会利用VR全景技术带领着新生进行校园游览&#xff0c;给予新生们巨大便利的同时&a…...

el-checkbox-group限制勾选数量

<!--* Description: 视频监控 页面* Author: mhf* Date: 2023-08-15 13:26:33 --> <template><div class"videoSurveillance"><el-row :gutter"24"><el-col :span"4"><div class"videoSurveillance-left&…...

【JavaScript】WebAPI入门到实战

文章目录 一、WebAPI背景知识1. 什么是WebAPI&#xff1f;2. 什么是API&#xff1f; 二、DOM基本概念三、获取元素三、事件初识1. 点击事件2. 键盘事件 四、操作元素1. 获取/修改元素内容2. 获取/修改元素属性3. 获取/修改表单元素属性4. 获取/修改样式属性 五、操作节点1. 新增…...

奥康的高尔夫鞋,圈不住投资者的心

文 | 螳螂观察 作者 | 青月 鞋服行业终于熬过了“寒冬”&#xff0c;2023年行业景气度开始逐步回暖。 东方财富Choice数据显示&#xff0c;截至8月17日&#xff0c;已有28家鞋帽服装类上市公司发布了2023年中期业绩预告或快报&#xff0c;其中&#xff0c;9家预增&#xff0…...

vue2配置环境变量并且nginx运行成功

需求&#xff1a;我在vue项目配置了生产环境和开发环境&#xff0c;之后通过proxy代理的方式把地址转发到真实的服务器地址上用于请求接口&#xff0c;之后把项目打包后上传到nginx上&#xff0c;之后接口报错404&#xff0c;但是本地运行是可以访问的&#xff0c;找了很久终于…...

Java+Swing形成GUI图像界面

一、Swing 简介 Swing 主要用来开发 GUI 程序,GUI(Graphical User Interface)即图形用户界面。Java 中针对 GUI 设计提供了丰富的类库,这些类分别位于 java.awt 和 java.swing 中,简称 AWT 和 Swing ;其中,AWT(Abstract Window Toolkit)是抽象窗口工具包,是 Java 平…...

编辑距离 -- 动规

72. 编辑距离 给出动规的两种常见实现形式&#xff1a;自顶向下、自底向上&#xff0c;前者一般借助递归函数备忘录实现&#xff0c;后者通常基于dp数组实现。 class MinDistance:"""72. 编辑距离https://leetcode.cn/problems/edit-distance/""&quo…...

douyin【商品抢购js脚本】

文章目录 前言订阅须知知识点源码前言 脚本主要用来实现抢购douyin商城、直播间秒杀商品等一系列商品 订阅须知 订阅后,只提供js源代码,不提供教学,请根据源码自行抓包知识点 1、在查询串插入一个固定的键rstr   2、对查询串进行按键排序并取值,对空格和+进行转义为a …...

常见Web安全技术总结!474页Web安全从入门到精通(附PDF)

Web安全范围比较大&#xff0c;知识点比较杂&#xff0c;很多朋友都无从下手&#xff0c;这不可怕&#xff0c;可怕的是乱下手&#xff0c;其实往往基础才是决定你是否能走远的关键。 为了帮助大家入门网安&#xff0c;给大家推荐一份《新手Web安全入门到精通》&#xff0c;共…...

Prometheus 监控指南:如何可靠地记录数字时间序列数据

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…...

rsync远程同步+inotify监控

目录 一、Rsync 简介 1、rsync是什么 2、备份的方式 3、rsync同步方式 4、常用rsync命令 5、配置源的两种表达方法 二、rsync实验 1、本地复制 ​编辑​编辑 2、异地复制 2.1 rsync服务器配置 2.2 rsync客户端配置 2.2.1 普通同步 2.2.2 免密同步 2.2.3 --delet…...

【面试经典150 | 数组】移除元素

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;原地操作 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等…...

玩转Mysql系列 - 第21篇:什么是索引?

这是Mysql系列第21篇。 本文开始连续3篇详解mysql索引&#xff1a; 第1篇来说说什么是索引&#xff1f; 第2篇详解Mysql中索引的原理 第3篇结合索引详解关键字explain 本文为索引第一篇&#xff1a;我们来了解一下什么是索引&#xff1f; 路人在搞计算机之前&#xff0c;…...

预处理指令

// The include directive instructs the preprocessor to paste the text of the given file into the current file. // 粘贴指定文件的内容 #include // 定义宏PI #define PI 3.1415926 // 取消定义PI #undef PI条件编译(Conditional Compilation) // 检查xxx是否已被定义为…...

强大的JTAG边界扫描(1):基本原理介绍

文章目录 1. 什么是边界扫描&#xff1f;2. JTAG硬件接口3. 边界扫描相关的软硬件4. 学习资料5. 总结 我是怎么了解到边界扫描的呢&#xff1f; 这就要从我淘到一块FPGA板卡的事情说起了。 前段时间我在某二手平台上淘了一块FPGA板子&#xff0c;它长这样&#xff1a; 板子的…...

【C++】源文件.cpp和头文件.h分离编程

优势介绍 将C代码分为头文件&#xff08;.h&#xff09;和源文件&#xff08;.cpp&#xff09;的做法有以下几个好处&#xff1a; 模块化和代码组织&#xff1a;将函数和类的声明&#xff08;包括函数原型、类的成员和属性等&#xff09;放在头文件中&#xff0c;将函数和类的…...

报错ssh: Could not resolve hostname

…按照网上好多教程试了一下&#xff1a; 新建密钥&#xff0c;添加到gitee&#xff0c;重新测试。修改host&#xff0c;加入gitee的ip地址到里面去。修改.gifconfig配置文件&#xff0c;配置成ssh的仓库链接。 这上面的方法都不行&#xff0c;后面发现一篇文章&#xff1a;SS…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

Appium下载安装配置保姆教程(图文详解)

目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...