s3c2440 Learning Road-011 Code Relocation

Publisher:EuphoricVoyageLatest update time:2020-04-19 Source: eefocusKeywords:s3c2440  sdram Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1 Basic principles

Following the last blog s3c2440 learning path-010 sdram, sdram has been initialized, and now the value of SDRAM can be officially brought into play. (SDRAM can be read and written at will, and the subsequent codes will be placed on it to run)


1.1 Division of program segments

After a program is compiled, there will be a code segment, a data segment, a read-only data segment, a bss segment, and a comment segment.

image.png

Here we mainly talk about why the bss segment can reduce the size of the bin file. The bbs mainly records the location of global (static-modified local) variables that are not initialized or initialized to 0, but does not record their specific data, because the value of this part is set to 0 by default.


Here are 2 small programs


test1.c


#include


char a[1000];


int main(int argc, char *argv)

{


    return 0;

}


test2.c


#include


char a[1000] = {1};


int main(int argc, char *argv)

{


    return 0;

}


test1.c defines an array of 1 char[1000], does not initialize it, and saves it in the bss segment. The size of the compiled bin file is 8756B.

test2.c also defines an array of chart1000], but initializes it and saves it in the data segment. The size of the compiled bin file is 9592B.


Because the data of test1.c is stored in the bss segment, and bss only records its location, it does not require a large storage space. However, test2.c needs to store the entire array value in the data segment, so it needs to be at least 1000Byte larger than the bin of test1.c. It should be noted that only the size of the bin file is reduced, and the memory size consumed when the code is actually running is the same.

insert image description here

1.2 Why do we need to relocate code?

When using nand to boot, due to the characteristics of 2440, only the first 4K of code can be run (the first 4K will be automatically copied to the internal sram), so it is impossible to run a 100K+ uboot.bin, so the code needs to be relocated to the external SDRAM.


When using nor to start, the nor on the jz2440 development board is 2MB, which is enough to store general programs. However, nor can be read at will but not written at will, which means that global variables cannot be modified. Because modifying global variables requires rewriting the values ​​into nor, and nor cannot be written at will, writing values ​​will fail. Therefore, the code also needs to be relocated to the external SDRAM. (Local variables can be modified because local variables are placed in the stack, which is generally set in the sram inside the 2440)


1.3 How to implement relocation

It is very simple to implement relocation. First, copy all the codes to SDRAM. Second, jump the code to SDRAM to run, which means modifying the value of PC.


To copy code to SDRAM, you need to figure out where to start copying, how big to copy, and whether there is any order or rule.

1) The code is placed in NOR/NAND, so it should be copied from NOR/NAND. When burning the code, it starts from the address 0 of NOR/NAND, so it should be copied from the address 0 of NOR/NAND.

2) The program is divided into code segment, data segment, read-only data segment, bss segment and comment segment, so all this data must be copied into SDRAM, but what is the specific size? I will briefly talk about the lsd link script later, and this script can tell you the size of the program.

3) The order can be set by the lds linker script, but the general order is code segment -> read-only data segment -> data segment -> bss segment.


1.4 lds linker script

Because I haven't done an in-depth study of the lsd linker script, I only know how to use it simply. For detailed usage, please refer to the official documentation at http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.es.html. Here I only comment on the lds linker script I use.


test.lds


SECTIONS {

// . represents the current position, set the current position to 0x30000000, 0x30000000 is the starting address of SDRAM

    . = 0x30000000 ;

// 4-byte alignment

    . = ALIGN(4);

    //Define a variable __copy_code_start = the current position, which is 0x30000000

    __copy_code_start = . ;

    //Code snippet

    .text :

    {

    //Store the code segment of start.o first, because start.o is the first file to be run

        start.o

        //* indicates all, code snippets for all files

        *(.text)

    }


    . = ALIGN(4);

    //Read-only data segment for all files

    .rodata : { *(.rodata) }


    . = ALIGN(4);

    //Data segment of all files

    .data : { *(.data) }


    . = ALIGN(4);

    //Define variable __bss_start = current position, the current position is equal to 0x30000000 + code segment of all files + read-only data segment of all files + data segment of all files

    __bss_start = . ;

    //The bss segment and comment segment of the file

    .bss : { *(.bss) *(.COMMON) }

    //Define variable __end = current position, the current position is equal to __bss_start + bss segment and comment segment of all files

    __end = . ;

}


From the test.lds script, we can know that the storage order of the program is: text->text->rodata->data->bss of start.o. A total of three variables are defined, __copy_code_start, __bss_start, and __end.


When compiling, you can use the link script by using -T. Because the first sentence of the link script ". = 0x30000000;" sets the current position to 0x30000000, so the starting position of the dis file is 0x30000000 when disassembling. When you burn the generated bin file into nor/nand, it will still be copied from the 0 position of nor/nand. After reset, PC=0, and the program still runs from address 0. Therefore, 0x30000000 in the dis file will not have any effect on the code. The __copy_code_start, __bss_start, and __end are what you need for programming later.


Makefile

insert image description here

test.dis

insert image description here

2 Source code explanation

2.1 Main Process

start.s


/* Initialize external sdram */

    bl bank6_sdram_init


/* Copy code from NOR to SDRAM */

    /* copy .data .rodata. .text to SDRAM */

    bl copy2sdram


/* Clear bss segment */

    /* clear bss segment */

    bl clear_bss

/* Initialize the serial port */

    bl uart0_init

/* Print position value */

    bl print_position

/* Jump to main to execute */

    ldr pc, =main /* abs jump to main */


There will be some other initializations before start.s, but I will skip them all and only look at the most important parts. The initialization of SDRAM was discussed in the previous blog, so I will not introduce it here.


2.2 Copying text, data, and rodata segments

init.c


void copy2sdram(void)

{

    extern int __copy_code_start, __bss_start;


    volatile unsigned int *src = (unsigned int *)0;

    volatile unsigned int *dst = (unsigned int *)&__copy_code_start;

    volatile unsigned int *end = (unsigned int *)&__bss_start;


    while(dst < end)

    {

        *dst++ = *src++;

    }

}


__copy_code_start, __bss_start are variables in the link script, which refer to external variables, so extern is required. The current program only supports the relocation of nor, while 2440 can directly access nor, so src=0 means the address 0 of nor. &__copy_code_start means taking the value of the variable __copy_code_start, which is also 0x30000000. The expression here is different from C language. C language takes the address of the variable, while __copy_code_start is a variable in the link script, so it is used differently. You can remember this as a rule. Similarly, end = &__bss_start also takes the value of __bss_start, 0x30001000.


The main function of this code is to copy the data at address nor 0 to address 0x30000000, with a length of end - dst = &__bss_start - &__copy_code_start = 0x30001000 - 0x30000000 = 0x1000. Only text, data, and rodata are copied here, and the bss segment is not copied. Next, the bss segment will be processed. (0x30000000 is the starting address of SDRAM. Copying to this address means copying to SDRAM. If you don’t understand, please read the previous blog)


2.3 Clear the bss segment

init.c


void clear_bss(void)

{

    extern int __bss_start, __end;

    volatile unsigned int *src = (unsigned int *)&__bss_start;

    volatile unsigned int *end = (unsigned int *)&__end;


    while(src <= end)

    {

        *src++ = 0;

    }

}


Similarly, extern is required to reference __bss_start and __end link script variables. Here, &__bss_start and &__end are also used to obtain their values. src = &__bss_start = 0x30001000, end = &__end = 30001008. The main function of this code is to clear the data from 0x30001000 to 0x30001008. When copying the code, do not copy the bss segment, so this data is all 0, so you only need to record the starting and ending positions of bss, and then clear it. This also corresponds to what was said before, the bss segment can reduce the size of the bin file.


2.4 Print __copy_code_start, __bss_start, __end

init.c


void print_positon(void)

{

    extern int __copy_code_start, __bss_start, __end;


    volatile unsigned int *code_start = (unsigned int *)&__copy_code_start;

    volatile unsigned int *bss_start= (unsigned int *)&__bss_start;

    volatile unsigned int *end= (unsigned int *)&__end;


    printf("code_start:%xn", code_start);

    printf("bss_start:%xn", bss_start);

    printf("end:%xn", end);

}


The function of print_positon is to print the values ​​of __copy_code_start, __bss_start, and __end, so you need to call bl uart0_init first to initialize the serial port.

insert image description here

2.5 Program Jump

start.s finally executes ldr pc, =main to assign pc to the value of main. From the dis file, we can see that the statement corresponding to ldr pc, =main is ldr pc, [pc, #16]. pc + 16 = 0x30000088, the value at the position of 0x30000088 is 0x30000af8, which happens to be the value of main. Therefore, ldr pc, =main is equal to pc=0x30000af8, and the program starts running on SDRAM.


It should be noted here that before executing ldr pc, =main, the program is running on nor, so the address of the program cannot exceed 2M. Although the starting address of the program is 0x30000000, the actual value of PC needs to be subtracted by 0x30000000. Although the displayed address is 0x30000000+, the program is burned from the address 0 of nor. After reset, the program starts to fetch instructions from the address 0 of nor, which is also the corresponding 0x30000000. Therefore, PC increases from 0, not from 0x30000000, until the value of PC is truly equal to the value displayed in the dis file after executing ldr pc, =main.

[1] [2]
Keywords:s3c2440  sdram Reference address:s3c2440 Learning Road-011 Code Relocation

Previous article:【s3c2440】Lesson 3: Code Relocation
Next article:Code relocation of s3c2440

Recommended ReadingLatest update time:2024-11-23 18:29

ARM-Linux s3c2440 UART Analysis (Part 3)
Looking back at the above, the underlying driver of the s3c2440 serial port revolves around three data structures: UART specific driver structure definition: struct uart_driver s3c24xx_uart_drv; UART port structure definition: struct uart_port s3c24xx_serial_ops; UART related operation function structure definitio
[Microcontroller]
S3C2440 Input Subsystem Study Notes Section 1
  I have been exposed to S3C2440 for a while, but I have never persisted in studying. As a recent graduate, I was deeply affected by my lack of skills and the pressure at work, so I decided to change my past and insist on studying every day after work. Here I don’t I dare to say that I can finish learning 2440, becaus
[Microcontroller]
S3C2440 Test Program (VI) LCD Display Experiment 2_ Touch the small picture to switch to the large picture
Experimental effect:     Click on the 6 small pictures on the screen to switch the small pictures to full-screen pictures. 1. To realize the small pictures, the original pictures need to be compressed, here compressed to 1/8 of the original. The code is as follows: void Paint_Bmp_Small(int x0,int y0,int h,int l,int k
[Microcontroller]
Use of S3C2440 timer
#include "mytimer.h" #include "lhg_def.h" #include "uart.h" #include "lhg_def.h" #include "2440addr.h" //Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value} //PCLK=50Mhz //prescaler : 0~255 #define prescaler234 99 //divider : 1/2,1/4,1/8,1/16 select (0,1,2,3) #define divider4 2 //Timer is set t
[Microcontroller]
S3C2440 watchdog
The main function of the watchdog timer is to reset the system when the program runs away due to interference, thereby preventing the system from running away and improving system stability. Let's first talk about the working principle of the watchdog: suppose the time for a complete running cycle of the system progra
[Microcontroller]
S3C2440 watchdog
S3C2440 memory initialization
It is divided into three parts:  ①2440 address space  ②Memory and chip hardware connection  ③Storage controller register S3C2440 Address Space S3C2440 provides 27 address lines to the outside. With only 27 pins on the chip, it can only access 128MB of peripheral space.  In order to expand the access range of peripher
[Microcontroller]
The difference between STM32 and S3C2440
1. Positioning STM32: High-function microcontroller, industrial control S3C2440: Processor, smart devices 2. Run the system STM32:    ucos-II S3C2440: Linux and other large systems 3. Hardware Architecture STM32: Cortex-M3, no MMU, small Flash and RAM space  S3C2440: ARM920T, with MMU, Flash and RAM external space  4.
[Microcontroller]
Embedded driver writing simple driver Hello_word
Development Environment BootLoader: u-boot-1.1.6 kernel:linux-2.6.30.4 cpu:S3C2440 step 1. Write driver code This should be the simplest driver, which only prints information in the kernel. The code is as follows: #include linux/module.h #include linux/kernel.h MODULE_LICENSE("GPL");                 static in
[Microcontroller]
Embedded driver writing simple driver Hello_word
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号