logo资料库

GCC链接文件解析与代码数据位置重分配.pdf

第1页 / 共18页
第2页 / 共18页
第3页 / 共18页
第4页 / 共18页
第5页 / 共18页
第6页 / 共18页
第7页 / 共18页
第8页 / 共18页
资料共18页,剩余部分请下载后查看
Freescale Semiconductor Relocating Code and Data Using the KDS GCC Linker File (.ld) for Kinetis By: Technical Information Center 1) Introduction Contents for This document provides guidance relocating Code and Data within the MCU memory map. As part of this process it explains how create new memory segments and sections by editing the GCC Linker File (.ld) for Kinetis Architectures. For detailed information on the GCC Linker please refer to “The GNU Linker” by Steve Chamberlain and Ian Lance Taylor. 2) Preliminary Background A linker or link editor is a program that takes one or more objects generated by the compiler to combine them, relocate their data and tie up symbol references to generate an executable file. This is usually the last step in compiling a program, to do it the linker uses a linker file or linker script. In order to relocate code and data in a specific memory area it is necessary to edit the linker file. The following chapters explain how the linker place functions in the memory and how to relocate them in flash, internal RAM, and external RAM using K60 or K70 Kinetis devices with Kinetis Design Studio and GCC toolchain. 1 Introduction 2 Preliminary Backgrounds 3 Linker File (.ld) Overview 4 Relocating Code 4.1 Prerequisites 4.2 Relocating Code in ROM 4.3 Relocating Code in RAM 4.4 Relocating Code in a Specific RAM address 4.5 Relocating Code in External RAM 5 Relocating Data 6 Linker File for RAM Project
3) Linker File (.ld) Overview Freescale linker files are divided in 2 main parts. 3.1) Memory Segment The memory segment is used to divide the Microcontroller memory into segments. Each segment can have read, write and execute attributes. The address and the length of each segment are defined as well. An example is shown in listing 1. MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBF0 m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000 m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000 } Listing 1 – K70 Memory segment 3.2) Sections Segment In sections segment are defined the contents of target-memory sections. In other words, a section indicates which parts of your application will be allocated in each memory segment. Main sections are ‘.text’ which contains all the code and the constants of an application, ‘.data’ which contains all initialized data, and ‘.bss’ which contains all non-initialized data. Below you can see section ‘.text’ of an application using K70. As you can notice it is contained in segment ‘m_text’. .text : { . = ALIGN(4); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) . = ALIGN(4); } > m_text Listing 2 – K70 section .text 4) Relocating Code The code generated by the compiler is usually placed in section ‘.text’. However, sometimes it is necessary to have certain particular functions to appear in special sections or in a specific address. The ‘section’ attribute specifies that a function lives in a particular section. e.g. void vfnDummy (void) __attribute__ ((section ("mySec"))); The example above places function ‘vfnDummy’ in section ‘mySec’. In this application note we are going to write 6 functions that toggle the TWR-K60 or TWR-K70 on board LEDs when pushing an onboard switch (SW2). Such functions are going to be allocated/relocated in different memory areas.
4.1) Prerequisites  Create a new Kinetis Design Studio project using K60 or K70.  Before using the GPIOs you need to initialize them, use function init_gpio() shown in listing 3 for this purpose. You will also need function delay() shown in listing 4 to provide a short delay. The following defines are necessary as well. #define GPIO_PIN_MASK 0x1Fu #define GPIO_PIN(x) (((1)<<(x & GPIO_PIN_MASK))) void init_gpio() { } /* Enable all of the port clocks */ SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK | SIM_SCGC5_PORTF_MASK ); // Set PTD0 and PTE26 (connected to SW1 and SW2) for GPIO functionality, falling IRQ, // and to use internal pull-ups. (pin defaults to input state) PORTD_PCR0=PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA)|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK; PORTE_PCR26=PORT_PCR_MUX(1)|PORT_PCR_IRQC(0xA)|PORT_PCR_PE_MASK|PORT_PCR_PS_MASK; // Set PTA10, PTA11, PTA28, and PTA29 (connected to LED's) for GPIO functionality PORTA_PCR10=(0|PORT_PCR_MUX(1)); PORTA_PCR11=(0|PORT_PCR_MUX(1)); PORTA_PCR28=(0|PORT_PCR_MUX(1)); PORTA_PCR29=(0|PORT_PCR_MUX(1)); // Change PTA10, PTA11, PTA28, PTA29 to outputs */ GPIOA_PDDR=GPIO_PDDR_PDD(GPIO_PIN(10) | GPIO_PIN(11) | GPIO_PIN(28) | GPIO_PIN(29) ); Listing 3 – Function init_gpio void delay() { unsigned int i, n; for(i=0;i<3000;i++) { for(n=0;n<1000;n++) { __asm("nop"); } } } Listing 4 – Function delay Call function init_gpio from function main, then enter in and endless loop calling function delay inside the loop. Function main must look as shown in listing 5. int main (void) { } init_gpio(); while(1) { } return 0; delay(); Listing 5 – Function main Go to menu Project > Build Configurations > Set Active > Debug. Then go to menu Project > Build Project to build the project. You can alternately click the hammer button.
4.2) Relocating Code in ROM Listing 6 shows function toggle_LED_allocated_in_Flash which toggles blue LED 3 times. Copy this function into your project and call it each time SW2 is pressed. Function main must look as shown in listing 7. /*Toggle LEDs - This functions toggles blue LED*/ void toggle_LED_allocated_in_Flash() { } unsigned int x; for(x = 0; x < 6; x++ ) { } GPIOA_PTOR|=GPIO_PDOR_PDO(GPIO_PIN(10)); delay(); Listing 6 – Function toggle_LED_allocated_in_Flash int main (void) { } init_gpio(); while(1) { } return 0; //Look at status of SW2 on PTE26 if((GPIOE_PDIR & GPIO_PDIR_PDI(GPIO_PIN(26)))==0) //If pressed... { } delay(); toggle_LED_allocated_in_Flash(); Listing 7 – Function main Go to menu Project > Build Project and then search for the *.map file inside {Project_path}/Debug. Here you can see that function toggle_LED_allocated_in_Flash is placed in a flash address. This is shown in listing 8. .text.toggle_LED_allocated_in_Flash 0x00000710 0x3c ./Sources/main.o 0x00000710 toggle_LED_allocated_in_Flash Listing 8 – Function toggle_LED_allocated_in_Flash in map file Now we are going to use attribute ‘section’ to create a section. This time the section is called ‘.myROM’ and use it to relocate a function that toggles on-board green LED in address 0x000FF000. Listing 9 shows how this function should see. /*Toggle LEDs - This functions toggles green LED and is relocated in Flash address 0x0000FF00*/ __attribute__ ((section(".myROM"))) void toggle_LED_relocated_in_Flash_address_0x000FF000() { } unsigned int x; for(x = 0; x < 6; x++ ) { } GPIOA_PTOR|=GPIO_PDOR_PDO(GPIO_PIN(29)); delay(); Listing 9 – Function toggle_LED_relocated_in_Flash_address_0x000FF000
Now we need to edit linker file (.ld) to create a new segment where this function is going to be relocated. Compare listing 10 with listing 1 and notice that 0x1000 bytes were subtracted from segment ‘m_text’ to create segment ‘my_text’. MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBF0 - 0x1000 my_text (RX) : ORIGIN = 0x000FF000, LENGTH = 0x00001000 /* New ROM Segment */ m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000 m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000 } Listing 10 – Memory segment edited to create segment ‘my_text’ Now create a new section in linker file to place ‘.myROM’ content. You can call this section ‘.my_ROM’ and write it just before section ‘.data’. /* Section created to relocate code in specific Flash address */ .my_ROM : { } > my_text . = ALIGN(4); *(.myROM) . = ALIGN(4); Listing 11 – Section .my_ROM Finally, write a call to function toggle_LED_relocated_in_Flash_address_0x000FF000 after SW2 is pressed in function main. int main (void) { } //Look at status of SW2 on PTE26 if((GPIOE_PDIR & GPIO_PDIR_PDI(GPIO_PIN(26)))==0) //If pressed... { } delay(); init_gpio(); while(1) { } return 0; toggle_LED_allocated_in_Flash(); toggle_LED_relocated_in_Flash_address_0x000FF000(); Listing 12 – Section .my_ROM Go to menu Project > Build Project and then search for the *.map file inside {Project_path}/Debug. Here you can see that function toggle_LED_relocated_in_Flash_address_0x000FF000 is placed exactly where it is expected and it is 3c bytes long. This is shown on listing 13. .my_ROM 0x000ff000 0x3c 0x000ff000 . = ALIGN (0x4) *(.myROM) .myROM 0x000ff000 0x3c ./Sources/main.o 0x000ff000 toggle_LED_relocated_in_Flash_address_0x000FF000 0x000ff03c . = ALIGN (0x4) Listing 13 – Function toggle_LED_relocated_in_Flash_address_0x000FF000 in map file
4.3) Relocating Code in RAM Sometimes it is required to copy code to RAM for faster execution. The easiest way to do this is to add the function to section ‘.data’. Doing this the linker will place the function in the first address available in RAM and the startup code will copy the function form Flash to RAM automatically. Please notice that this approach only works if you don’t need to place the function in any specific RAM address. Next chapter discusses how to relocate a function in a specific RAM location. There are just 2 steps:  Use attribute ‘section’ to place the function in a new section. In this case it is called ‘.mydata’ as shown in listing 14.  Add content of ‘.mydata’ in ‘.data’ section as shown on listing 15. /*Toggle LEDs - This functions toggles orange and is relocated in RAM*/ __attribute__ ((section(".mydata"))) void toggle_LED_relocated_in_any_RAM_address() { } int x; for(x = 0; x < 6; x++ ) { } GPIOA_PTOR|=GPIO_PDOR_PDO(GPIO_PIN(28)); delay(); Listing 14 – Function toggle_LED_relocated_in_any_RAM_address /* Initialized data sections goes into RAM, load LMA copy after code */ .data : AT(__DATA_ROM) { . = ALIGN(4); __DATA_RAM = .; __data_start__ = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ *(.mydata) KEEP(*(.jcr*)) . = ALIGN(4); __data_end__ = .; /* define a global symbol at data end */ } > m_data /* .mydata relocates a function on any RAM address */ Listing 15 – Adding content of ‘.mydata’ in ‘.data’ section Write a call to function toggle_LED_relocated_in_any_RAM_address after SW2 is pressed in function main. int main (void) { } //Look at status of SW2 on PTE26 if((GPIOE_PDIR & GPIO_PDIR_PDI(GPIO_PIN(26)))==0) //If pressed... { } delay(); init_gpio(); while(1) { } return 0; toggle_LED_allocated_in_Flash(); toggle_LED_relocated_in_Flash_address_0x0000FF00(); toggle_LED_relocated_in_any_RAM_address(); Listing 16 – Function main
Go to menu Project > Build Project and then search for the *.map file inside {Project_path}/Debug. Here you can see that function toggle_LED_relocated_in_any_RAM_address is placed in RAM and it is 40 bytes long. This is shown on listing 17. .data 0x20000000 0x2ec load address 0x00000cc0 0x20000000 . = ALIGN (0x4) 0x20000000 __DATA_RAM = . 0x20000000 __data_start__ = . *(.data) *(.data*) .data.impure_data 0x20000000 0x298 c:/freescale/kds_2.0.0/toolchain/bin/../lib/gcc/arm-none- eabi/4.8.0/../../../../arm-none-eabi/lib/m4/fp/v4-sp-d16\libg_s.a(lib_a-impure.o) .data._impure_ptr 0x20000298 0x4 c:/freescale/kds_2.0.0/toolchain/bin/../lib/gcc/arm-none- eabi/4.8.0/../../../../arm-none-eabi/lib/m4/fp/v4-sp-d16\libg_s.a(lib_a-impure.o) 0x20000298 _impure_ptr *(.mydata) .mydata 0x2000029c 0x3c ./Sources/main.o 0x2000029c toggle_LED_relocated_in_any_RAM_address Listing 17 – Function toggle_LED_relocated_in_any_RAM_address in map file 4.4) Relocating Code in a specific RAM address To relocate a function in a specific RAM section it is necessary to create a new memory segment and a new section in the linker file. Be aware that you must save this function in Flash and then it must be copied to RAM. The startup code can do this copy for us if we create a new Loop to copy data from read only memory to RAM in our Startup File. The first step is to write the function using attribute ‘section’. In this example the section is called ‘myRAM’. /*Toggle LEDs - This functions toggles red LED and is relocated in RAM address 0x1FFFE000*/ __attribute__ ((section(".myRAM"))) void toggle_LED_relocated_in_RAM_address_0x2000E000 () { } unsigned int x; for(x = 0; x < 6; x++ ) { } GPIOA_PTOR|=GPIO_PDOR_PDO(GPIO_PIN(11)); delay(); Listing 18 – Function toggle_LED_relocated_in_RAM_address_0x1FFFE000 Next step is to create a segment in the linker file. This segment must start in the address where the function needs to be relocated; in this case it is address 0x1FFFE00. Notice that 0x2000 bytes are subtracted from segment ‘m_data’ to create segment ‘my_data’. MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBF0 - 0x1000 my_text (RX) : ORIGIN = 0x000FF000, LENGTH = 0x00001000 /* New ROM Segment */ m_data (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000 - 0x2000 my_data (RW) : ORIGIN = 0x2000E000, LENGTH = 0x00002000 /* New RAM Segment */ m_data_1FFF0000 (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000 } Listing 19 – Memory segment edited to add segment my_data Then a section must be created in the linker file, this section must be contained in segment ‘my_data’, let us call it ‘.my_ram’. As it was mentioned before, the function must be saved in flash and copied to RAM in
run time. The instruction ‘AT’ indicates the flash address where the function will be resident before being copied. If you search the for label ‘__DATA_ROM’ in the linker file you will find that it points to the first available address in flash, here is where section ‘.data’ is resident, therefore, the address where section ‘.my_ram’ must reside is after section ‘.data’. To calculate this address the instruction ‘SIZEOF’ is used. This is shown in listing 20. /* Section created to relocate code in specific RAM address */ .my_ram : AT(__DATA_ROM + SIZEOF(.data)) { __myRam_start__ = .; __myRam_end__ = .; } > my_data . = ALIGN(4); _mySection = .; /* create a global symbol at myRAM */ *(.myRAM) . = ALIGN(4); Listing 20 – Section .my_ram As we inserted a new RAM section that was not considered by the linker we must make a couple of adjustments. At this moment label __m_data_1FFF0000_ROMStart overlaps with the address where section ‘.my_ram’ resides. This label must be edited to skip section ‘.my_ram’. __m_data_1FFF0000_ROMStart = __DATA_ROM + SIZEOF(.data) + SIZEOF(.my_ram); The last step is to copy the code from flash to RAM. To do this it is necessary to add a new Loop to copy data from read only memory to RAM in the startup_MK70F12.S file: /* Loop to copy data from read only memory to RAM. The ranges * of copy from/to are specified by following symbols evaluated in * linker script. * __DATA_END: End of code section, i.e., begin of data sections to copy from. * __new_start__/__new_end__: RAM address range that data should be * copied to. Both must be aligned to 4 bytes boundary. */ ldr r1, =__DATA_END ldr r2, =__myRam_start__ ldr r3, =__myRam_end__ /* New loop implementation */ .LC2: cmp r2, r3 ittt lt ldrlt r0, [r1], #4 strlt r0, [r2], #4 blt .LC2 Listing 2X – Loop to copy data from read only memory to RAM In function main write a call to function toggle_LED_relocated_in_RAM_address_0x2000E000 after SW2 is pressed. If you have added the functions in previous chapters, function main should look as follows. int main (void) { //Look at status of SW2 on PTE26 if((GPIOE_PDIR & GPIO_PDIR_PDI(GPIO_PIN(26)))==0) //If pressed... { init_gpio(); while(1) { toggle_LED_allocated_in_Flash(); toggle_LED_relocated_in_Flash_address_0x0000FF00(); toggle_LED_relocated_in_any_RAM_address(); toggle_LED_relocated_in_RAM_address_0x2000E000();
分享到:
收藏