7.1 About scatter-loading

The scatter-loading mechanism enables you to specify the memory map of an image to the linker using a description in a text file.

Scatter-loading gives you complete control over the grouping and placement of image components. You can use scatter-loading to create simple images, but it is generally only used for images that have a complex memory map. That is, where multiple memory regions are scattered in the memory map at load and execution time.
An image memory map is made up of regions and output sections. Every region in the memory map can have a different load and execution address.
To construct the memory map of an image, the linker must have:
  • Grouping information that describes how input sections are grouped into output sections and regions.
  • Placement information that describes the addresses where regions are to be located in the memory maps.
When the linker creates an image using a scatter file, it creates some region-related symbols. The linker creates these special symbols only if your code references them.
 

7.2 When to use scatter-loading

Scatter-loading is usually required for implementing embedded systems because these use ROM, RAM, and memory-mapped peripherals.

Situations where scatter-loading is either required or very useful:
Complex memory maps
Code and data that must be placed into many distinct areas of memory require detailed instructions on where to place the sections in the memory space.
Different types of memory
Many systems contain a variety of physical memory devices such as flash, ROM, SDRAM, and fast SRAM. A scatter-loading description can match the code and data with the most appropriate type of memory. For example, interrupt code might be placed into fast SRAM to improve interrupt response time but infrequently-used configuration information might be placed into slower flash memory.
Memory-mapped peripherals
The scatter-loading description can place a data section at a precise address in the memory map so that memory mapped peripherals can be accessed.
Functions at a constant location
A function can be placed at the same location in memory even though the surrounding application has been modified and recompiled. This is useful for jump table implementation.
Using symbols to identify the heap and stack
Symbols can be defined for the heap and stack location when the application is linked. 

7.4 Scatter-loading images with a simple memory map

For images with a simple memory map, you can specify the memory map using only linker command-line options, or with a scatter file.

If an image has a simple memory map, you can either:
  • Use a scatter file.
  • Specify the memory map using only linker command-line options.
The following figure shows a simple memory map:
Figure 7-1 Simple scatter-loaded memory map
The following example shows the corresponding scatter-loading description that loads the segments from the object file into memory:
LOAD_ROM 0x0000 0x8000       ; Name of load region (LOAD_ROM),
; Start address for load region (0x0000),
; Maximum size of load region (0x8000)
{
0x0000 0x8000 ; Name of first exec region (EXEC_ROM),
; Start address for exec region (0x0000),
; Maximum size of first exec region (0x8000)
{
* (+RO) ; Place all code and RO data into
; this exec region
}
SRAM 0x10000 0x6000 ; Name of second exec region (SRAM),
; Start address of second exec region (0x10000),
; Maximum size of second exec region (0x6000)
{
* (+RW, +ZI) ; Place all RW and ZI data into
; this exec region
}
}
The maximum size specifications for the regions are optional. However, if you include them, they enable the linker to check that a region does not overflow its boundary.
Apart from the limit checking, you can achieve the same result with the following linker command-line:
armlink --ro_base 0x0 --rw_base 0x10000
 

7.5 Scatter-loading images with a complex memory map

For images with a complex memory map, you cannot specify the memory map using only linker command-line options. Such images require the use of a scatter file.

The following figure shows a complex memory map:
Figure 7-2 Complex memory map
The following example shows the corresponding scatter-loading
description that loads the segments from the program1.o and program2.o
files into memory:
LOAD_ROM_1 0x0000              ; Start address for first load region (0x0000)
{
EXEC_ROM_1 0x0000 ; Start address for first exec region (0x0000)
{
program1.o (+RO) ; Place all code and RO data from
; program1.o into this exec region
}
DRAM 0x18000 0x8000 ; Start address for this exec region (0x18000),
; Maximum size of this exec region (0x8000)
{
program1.o (+RW, +ZI) ; Place all RW and ZI data from
; program1.o into this exec region
}
}
LOAD_ROM_2 0x4000 ; Start address for second load region (0x4000)
{
EXEC_ROM_2 0x4000
{
program2.o (+RO) ; Place all code and RO data from
; program2.o into this exec region
}
SRAM 0x8000 0x8000
{
program2.o (+RW, +ZI) ; Place all RW and ZI data from
; program2.o into this exec region
}
}

Caution

The scatter-loading description in this example specifies the location for code and data for program1.o and program2.o only. If you link an additional module, for example, program3.o, and use this description file, the location of the code and data for program3.o is not specified.
Unless you want to be very rigorous in the placement of code and data, it is advisable to use the * or .ANY specifier to place leftover code and data.
 

7.6 Scatter file with link to bit-band objects

In devices with the ARMv7-M architecture, the SRAM and Peripheral regions each have a bit-band feature.

You can access each bit in the bit-band region individually at a different address, called the bit-band alias. For example, to access bit[13] of the word at 0x20000001, you can use the address 0x22000054.
The following table shows the bit-band regions and aliases within the SRAM and Peripheral memory regions.

Table 7-1 ARMv7-M bit-band regions and aliases

Memory region
Description
Address range
SRAM
Bit-band region
0x20000000-0x200FFFFF
 
Bit-band alias
0x22000000-0x23FFFFFF
Peripheral
Bit-band region
0x40000000-0x400FFFFF
 
Bit-band alias
0x42000000-0x43FFFFFF
The following is an example scatter file that links bit-band objects.
FLASH_LOAD 0x20000000
{
RW 0x20000000 ; RW data at the start of bit band region
{
* (+RW-DATA)
}
RO + FIXED ; Followed by the RO Data
{
* (+RO-DATA)
}
CODEDATA + ; Followed by everything else
{
* (+RO-CODE)
* (+ZI) ; ZI follows straight after
}
ARM_LIB_HEAP + EMPTY 0x10000 ; heap starts after that
{
}
ARM_LIB_STACK 0x20100000 EMPTY -0x10000 ; stack starts at the
; top of bit band region
{
}
}

7.12 Methods of placing functions and data at specific addresses

There are various methods available to place functions and data at specific addresses.

Where they are required, the compiler normally produces RO, RW, ZI, and XO sections from a single source file. These sections contain all the code and data from the source file. To place a single function or data item at a fixed address, you must enable the linker to process the function or data separately from the rest of the input files.
The linker has two methods that enable you to place a section at a specific address:
  • You can create a scatter file that defines an execution region at the required address with a section description that selects only one section.
  • For a specially-named section the linker can get the placement address from the section name. These specially-named sections are called __at sections.
To place a function or variable at a specific address it must be placed in its own section. There are several ways to do this:
  • Place the function or data item in its own source file.
  • Use __attribute__((at(address))) to place variables in a separate section at a specific address.
  • Use __attribute__((section("name"))) to place functions and variables in a named section.
  • Use the AREA directive from assembly language. In assembly code, the smallest locatable unit is an AREA.
  • Use the --split_sections compiler option to generate one ELF section for each function in the source file.
    This option results in a small increase in code size for some functions because it reduces the potential for sharing addresses, data, and string literals between functions. However, this can help to reduce the final image size overall by enabling the linker to remove unused functions when you specify armlink --remove.

Example of how to place a variable at a specific address without scatter-loading

To place code and data at specific addresses without a scatter file:
  1. Create the source file main.c containing the following code:
    #include <stdio.h>
    extern int sqr(int n1);
    int gSquared __attribute__((at(0x5000))); // Place at 0x5000
    int main()
    {
    gSquared=sqr();
    printf("Value squared is: %d\n", gSquared);
    }
  2. Create the source file function.c containing the following code:
    int sqr(int n1)
    {
    return n1*n1;
    }
  3. Compile and link the sources:
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --map function.o main.o -o squared.axf
    The --map option displays the memory map of the image. Also, --autoat is the default.
In this example, __attribute__((at(0x5000))) specifies that the global variable gSquared is to be placed at the absolute address 0x5000. gSquared is placed in the execution region ER$$.ARM.__at_0x00005000 and load region LR$$.ARM.__at_0x00005000.

Note

Although the address is specified as 0x5000 in the source file, the region names and section name addresses are normalized to eight hexadecimal digits.
The memory map shows:

Load Region LR$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000000, Max: 0x00000004, ABSOLUTE) Execution Region ER$$.ARM.__at_0x00005000 (Base: 0x00005000, Size: 0x00000004, Max: 0x00000004, ABSOLUTE, UNINIT) Base Addr Size Type Attr Idx E Section Name Object 0x00005000 0x00000004 Zero RW .ARM.__at_0x00005000 main.o

Example of how to place a variable in a named section with scatter-loading

To modify your source code to place code and data in a specific section using a scatter file:
  1. Create the source file main.c containing the following code:

    #include <stdio.h>
    extern int sqr(int n1);
    int gSquared __attribute__((section("foo"))); // Place in section foo
    int main()
    {
    gSquared=sqr();
    printf("Value squared is: %d\n", gSquared);
    }
  2. Create the source file function.c containing the following code:

    int sqr(int n1)
    {
    return n1*n1;
    }
  3. Create the scatter file scatter.scat containing the following load region:
    LR1 0x0000 0x20000
    {
    ER1 0x0 0x2000
    {
    *(+RO) ; rest of code and read-only data
    }
    ER2 0x8000 0x2000
    {
    main.o
    }
    ER3 0x10000 0x2000
    {
    function.o
    *(foo) ; Place gSquared in ER3
    }
    ; RW and ZI data to be placed at 0x200000
    RAM 0x200000 (0x1FF00-0x2000)
    {
    *(+RW, +ZI)
    }
    ARM_LIB_STACK 0x800000 EMPTY -0x10000
    {
    }
    ARM_LIB_HEAP + EMPTY 0x10000
    {
    }
    }
    The ARM_LIB_STACK and ARM_LIB_HEAP regions are required because the program is being linked with the semihosting libraries.
  4. Compile and link the sources:
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --map --scatter=scatter.scat function.o main.o -o squared.axf
    The --map option displays the memory map of the image. Also, --autoat is the default.
In this example, __attribute__((section("foo"))) specifies that the global variable gSquared is to be placed in a section called foo. The scatter file specifies that the section foo is to be placed in the ER3 execution region.
The memory map shows:
  Load Region LR1 (Base: 0x00000000, Size: 0x00001570, Max: 0x00020000, ABSOLUTE)

Execution Region ER3 (Base: 0x00010000, Size: 0x00000010, Max: 0x00002000, ABSOLUTE) Base Addr Size Type Attr Idx E Section Name Object 0x00010000 0x0000000c Code RO .text function.o
0x0001000c 0x00000004 Data RW foo main.o

Note

If you omit *(foo) from the scatter file, the section is placed in the region of the same type. That is RAM in this example.

Example of how to place a variable at a specific address with scatter-loading

To modify your source code to place code and data at a specific address using a scatter file:
  1. Create the source file main.c containing the following code:
    #include <stdio.h>
    extern int sqr(int n1);
    // Place at address 0x10000
    const int gValue __attribute__((section(".ARM.__at_0x10000"))) = ;
    int main()
    {
    int squared;
    squared=sqr(gValue);
    printf("Value squared is: %d\n", squared);
    }
  2. Create the source file function.c containing the following code:
    int sqr(int n1)
    {
    return n1*n1;
    }
  3. Create the scatter file scatter.scat containing the following load region:
    LR1 0x0
    {
    ER1 0x0
    {
    *(+RO) ; rest of code and read-only data
    }
    ER2 +
    {
    function.o
    *(.ARM.__at_0x10000) ; Place gValue at 0x10000
    }
    ; RW and ZI data to be placed at 0x200000
    RAM 0x200000 (0x1FF00-0x2000)
    {
    *(+RW, +ZI)
    }
    ARM_LIB_STACK 0x800000 EMPTY -0x10000
    {
    }
    ARM_LIB_HEAP + EMPTY 0x10000
    {
    }
    }
    The ARM_LIB_STACK and ARM_LIB_HEAP regions are required because the program is being linked with the semihosting libraries.
  4. Compile and link the sources:
    armcc -c -g function.c
    armcc -c -g main.c
    armlink --no_autoat --scatter=scatter.scat --map function.o main.o -o squared.axf
    The --map option displays the memory map of the image.
The memory map shows that the variable is placed in the ER2 execution region at address 0x10000:

Execution Region ER2 (Base: 0x00001578, Size: 0x0000ea8c, Max: 0xffffffff, ABSOLUTE) Base Addr Size Type Attr Idx E Section Name Object 0x00001578 0x0000000c Code RO .text function.o
0x00001584 0x0000ea7c PAD
0x00010000 0x00000004 Data RO .ARM.__at_0x10000 main.o
In this example, the size of ER1 is uknown. Therefore, gValue might be placed in ER1 or ER2. To make sure that gValue is placed in ER2, you must include the corresponding selector in ER2 and link with the --no_autoat command-line option. If you omit --no_autoat, gValue is to placed in a separate load region LR$$.ARM.__at_0x10000 that contains the execution region ER$$.ARM.__at_0x.ARM.__at_0x10000.
 

7.15 Examples of using placement algorithms for .ANY sections

These examples show the operation of the placement algorithms for RO-CODE sections in sections.o.

The input section properties and ordering are shown in the following table:

Table 7-2 Input section properties for placement of .ANY sections

Name Size
sec1 0x4
sec2 0x4
sec3 0x4
sec4 0x4
sec5 0x4
sec6 0x4
The scatter file used for the examples is:
LR 0x100
{
ER_1 0x100 0x10
{
.ANY
}
ER_2 0x200 0x10
{
.ANY
}
}

Note

These examples have --any_contingency disabled.

Example for first_fit, next_fit, and best_fit

This example shows the situation where several sections of equal size are assigned to two regions with one selector. The selectors are equally specific, equivalent to .ANY(+R0) and have no priority.
    Execution Region ER_1 (Base: 0x00000100, Size: 0x00000010, Max: 0x00000010, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000100 0x00000004 Code RO sec1 sections.o
0x00000104 0x00000004 Code RO sec2 sections.o
0x00000108 0x00000004 Code RO sec3 sections.o
0x0000010c 0x00000004 Code RO sec4 sections.o
Execution Region ER_2 (Base: 0x00000200, Size: 0x00000008, Max: 0x00000010, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000200 0x00000004 Code RO sec5 sections.o
0x00000204 0x00000004 Code RO sec6 sections.o
In this example:
  • For first_fit the linker first assigns all the sections it can to ER_1, then moves on to ER_2 because that is the next available region.
  • For next_fit the linker does the same as first_fit. However, when ER_1 is full it is marked as FULL and is not considered again. In this example, ER_1 is completely full. ER_2 is then considered.
  • For best_fit the linker assigns sec1 to ER_1. It then has two regions of equal priority and specificity, but ER_1 has less space remaining. Therefore, the linker assigns sec2 to ER_1, and continues assigning sections until ER_1 is full.

Example for worst_fit

This example shows the image memory map when using the worst_fit algorithm.
    Execution Region ER_1 (Base: 0x00000100, Size: 0x0000000c, Max: 0x00000010, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000100 0x00000004 Code RO sec1 sections.o
0x00000104 0x00000004 Code RO sec3 sections.o
0x00000108 0x00000004 Code RO sec5 sections.o
Execution Region ER_2 (Base: 0x00000200, Size: 0x0000000c, Max: 0x00000010, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000200 0x00000004 Code RO sec2 sections.o
0x00000204 0x00000004 Code RO sec4 sections.o
0x00000208 0x00000004 Code RO sec6 sections.o
The linker first assigns sec1 to ER_1. It then has two equally specific and priority regions. It assigns sec2 to the one with the most free space, ER_2 in this example. The regions now have the same amount of space remaining, so the linker assigns sec3 to the first one that appears in the scatter file, that is ER_1.

Note

The behavior of worst_fit is the default behavior in this version of the linker, and it is the only algorithm available and earlier linker versions.
 

7.16 Example of next_fit algorithm showing behavior of full regions, selectors, and priority

This example shows the operation of the next_fit placement algorithm for RO-CODE sections in sections.o.

The input section properties and ordering are shown in the following table:

Table 7-3 Input section properties for placement of sections with next_fit

Name Size
sec1 0x14
sec2 0x14
sec3 0x10
sec4 0x4
sec5 0x4
sec6 0x4
The scatter file used for the examples is:
LR 0x100
{
ER_1 0x100 0x20
{
.ANY1(+RO-CODE)
}
ER_2 0x200 0x20
{
.ANY2(+RO)
}
ER_3 0x300 0x20
{
.ANY3(+RO)
}
}

Note

This example has --any_contingency disabled.
The next_fit algorithm is different to the others in that it never revisits a region that is considered to be full. This example also shows the interaction between priority and specificity of selectors - this is the same for all the algorithms.
    Execution Region ER_1 (Base: 0x00000100, Size: 0x00000014, Max: 0x00000020, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000100 0x00000014 Code RO sec1 sections.o
Execution Region ER_2 (Base: 0x00000200, Size: 0x0000001c, Max: 0x00000020, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000200 0x00000010 Code RO sec3 sections.o
0x00000210 0x00000004 Code RO sec4 sections.o
0x00000214 0x00000004 Code RO sec5 sections.o
0x00000218 0x00000004 Code RO sec6 sections.o
Execution Region ER_3 (Base: 0x00000300, Size: 0x00000014, Max: 0x00000020, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x00000300 0x00000014 Code RO sec2 sections.o
In this example:
  • The linker places sec1 in ER_1 because ER_1 has the most specific selector. ER_1 now has 0x6 bytes remaining.
  • The linker then tries to place sec2 in ER_1, because it has the most specific selector, but there is not enough space. Therefore, ER_1 is marked as full and is not considered in subsequent placement steps. The linker chooses ER_3 for sec2 because it has higher priority than ER_2.
  • The linker then tries to place sec3 in ER_3. It does not fit, so ER_3 is marked as full and the linker places sec3 in ER_2.
  • The linker now processes sec4. This is 0x4 bytes so it can fit in either ER_1 or ER_3. Because both of these sections have previously been marked as full, they are not considered. The linker places all remaining sections in ER_2.
  • If another section sec7 of size 0x8 exists, and is processed after sec6 the example fails to link. The algorithm does not attempt to place the section in ER_1 or ER_3 because they have previously been marked as full.
 

7.19 Placement of code and data with __attribute__((section("name")))

You can place code and data by separating them into their own objects without having to use toolchain-specific pragmas or attributes.

However, you can also use __attribute__((section("name"))) to place an item in a separate ELF section. You can then use a scatter file to place the named sections at specific locations.

Examples

To use __attribute__((section("name"))) to place a variable in a separate section:
  1. Use __attribute__((section("name"))) to specify the named section where the variable is to be placed, for example:
    Naming a section
    int variable __attribute__((section("foo"))) = ;
  2. Use a scatter file to place the named section, for example:
    Placing a section
    FLASH 0x24000000 0x4000000
    {
    … ; rest of code
    ADDER 0x08000000
    {
    file.o (foo) ; select section foo from file.o
    }
    }
The following example shows the memory map for the FLASH load region:

Load Region FLASH (Base: 0x24000000, Size: 0x00000004, Max: 0x04000000, ABSOLUTE)
Execution Region ADDER (Base: 0x08000000, Size: 0x00000004, Max: 0xffffffff, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x08000000 0x00000004 Data RW foo file.o
Be aware of the following:
  • Linking with --autoat or --no_autoat does not affect the placement.
  • If scatter-loading is not used, the section is placed in the default ER_RW execution region of the LR_1 load region.
  • If you have a scatter file that does not include the foo selector, then the section is placed in the defined RW execution region.
You can also place a function at a specific address using .ARM.__at_address as the section name. For example, to place the function sqr at 0x20000, specify:
int sqr(int n1) __attribute__((section(".ARM.__at_0x20000")));
int sqr(int n1)
{
return n1*n1;
}
 
 
 
 
 
 
 
 

7 Scatter-loading Features的更多相关文章

  1. 使用Python 将shapefile导入mongodb

    使用Python 将shapefile导入mongodb 随着big data时代的到来,各个行业都在考虑能不能把big data的思路.方法引入进来,GIS行业也不能免俗. 下面就介绍一下如何将sh ...

  2. Java_动态加载类(英文)

    It is possible to load and reload classes at runtime in Java, though it is not as straightforward as ...

  3. MongoDB的地埋空间数据存储、空间索引以及空间查询

    一.关于MongoDB 在众多NoSQL数据库,MongoDB是一个优秀的产品.其官方介绍如下: MongoDB (from "humongous") is a scalable, ...

  4. python data analysis | python数据预处理(基于scikit-learn模块)

    原文:http://www.jianshu.com/p/94516a58314d Dataset transformations| 数据转换 Combining estimators|组合学习器 Fe ...

  5. MDK 的编译过程及文件类型全解

    MDK 的编译过程及文件类型全解 ------(在arm9的开发中,这些东西都是我们自己搞定的,但是在windows上,IDE帮我们做好了,了解这些对深入开发是很有帮助的,在有arm9开发的基础上,下 ...

  6. sklearn特征抽取

    特征抽取sklearn.feature_extraction 模块提供了从原始数据如文本,图像等众抽取能够被机器学习算法直接处理的特征向量. 1.特征抽取方法之 Loading Features fr ...

  7. scikit-learn:在实际项目中用到过的知识点(总结)

    零.全部项目通用的: http://blog.csdn.net/mmc2015/article/details/46851245(数据集格式和预測器) http://blog.csdn.net/mmc ...

  8. 第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429系列

    第48章     MDK的编译过程及文件类型全解 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  9. KEIL下分散加载文件的使用(zt)

    KEIL下分散加载文件的使用   对于分散加载的概念,在<ARM体系结构与编程>书中第11章有明确介绍. 分散加载文件(即scatter file 后缀为.scf)是一个文本文件,通过编写 ...

  10. scikit-learn:4.2. Feature extraction(特征提取,不是特征选择)

    http://scikit-learn.org/stable/modules/feature_extraction.html 带病在网吧里. ..... 写.求支持. .. 1.首先澄清两个概念:特征 ...

随机推荐

  1. Android中的Handler,Looper,Message机制

    Android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...

  2. spring之循环依赖问题如何解决

    首先,spring是支持循环依赖的.但是循环依赖并不好. 最近,我在使用jenkins自动化部署,测试打出来的jar包,出现了循环依赖的问题. 在这里说一下,我解决问题的过程 我首先根据提示找到循环依 ...

  3. BZOJ 2326: [HNOI2011]数学作业(矩阵乘法)

    传送门 解题思路 NOIp前看到的一道题,当时想了很久没想出来,NOIp后拿出来看竟然想出来了.注意到有递推\(f[i]=f[i-1]*poww[i]+i\),\(f[i]\)表示\(1-i\)连接起 ...

  4. [NOIP模拟15]题解

    A.建设城市(city) 这容斥题多难啊你们是怎么考场切掉的啊 首先可以想一下,如果没有k的限制,这题怎么做? 相信你们肯定能看出来是挡板法裸题:m个物品分给n个人,每个人至少一个. 就是$C_{m- ...

  5. /etc/X11/xorg.conf

    # This configuration file was broken by system-config-keyboard Section "ServerLayout" Iden ...

  6. html select美化模拟jquery插件select2.js

    代码展示:http://www.51xuediannao.com/demo.php 代码说明: select2.js是一个html select美化模拟类jquery插件,但是select2.js又远 ...

  7. poj 3258 二分

    题意:看了很久才懂,有n个石头,去掉m个后,求跳两个石头或石头和岸边距离最小的最大值,就是至少要跳的距离的最大. 参考博客: 代码: #include<stdio.h> #include& ...

  8. PHP中的闭包小谈

    接触PHP一段时间以来,我一直以为这是一种基于函数式编程的语言是没有闭包这种东西的,但事实上却颠覆了我的想法,PHP竟然有闭包,下面我们一起来接触一下PHP的所谓的闭包. 根据PHP官网的定义来看,闭 ...

  9. NCM格式转换MP3格式

    首先下载软件: 百度网盘下载地址:https://pan.baidu.com/s/1I_HUQGBnOq23Zdm-NgbnqA 提取码:u4m5 下载完毕直接打开就好 添加NCM文件 点击开始转换 ...

  10. hdu5421 Victor and String 回文树(前后插入)

    题目传送门 题意:对一个字符串支持四种操作,前插入字符,后插入字符,询问本质不同的回文串数量和所有回文串的数量. 思路: 就是在普通回文树的基础上,维护suf(最长回文后缀)的同时再维护一个pre(最 ...