Statement: I am also transferred, not original, because others are Netease logs and cannot be directly transferred, so ...... Thanks for your originality! Let me understand some code in the startup. s file. 1. What is an arm image file, The arm image file is actually an executable file, including the bin or hex format, which can be directly burned into the ROM for execution. During the axd debugging process, we debug the axf file, which is actually an image file. It only adds a file header and some debugging information to the binfile. Generally, an image file consists of three output segments (RO, RW, and Zi. The so-called domain refers to the region where the entire bin image file is located. It is divided into loading and running domains. For embedded systems, program images are stored in some non-volatile devices such as flash memory. during runtime, the RW segment of the program must be reloaded into the read/write Ram. Simply put, the loading time domain of a program refers to the state in which the program is burned into flash, and the running time domain refers to the state in which the program is executed. In general, the address space of the entire binfile in Flash is to load the domain. Of course, the program will not be executed in flash, and will generally be moved to SDRAM to run the work, the address space in which they are moved to the SDRAM is the runtime domain. The entered Code generally includes the code part and data part. This is the so-called input segment. After compilation, it becomes the RO and RW segments in the binfile, and the so-called Zi segments, this is the output segment. In the integrated development environment of arm, read-only code segments and constants are called Ro segments (readonly). read-write global variables and static variables are called RW segments (readwrite ); the variable to be initialized to zero in the RW segment is called the Zi segment (zeroinit ). For the output segment in the loading field, generally the RO segment is followed by the RW segment, and the RW segment is followed by the Zi segment. These output segments are not consecutive in the running domain, but RW and Zi must be connected. Data in the Zi and RW segments can be RW attributes. 2. Simple address ing In simple mode, you can specify the RO base and RW base in the output of the arm linker option in the analyticdb integrated development environment, that is, inform the connector Ro and RW of the connection base address in simple mode. In this mode, arm linker outputs the following symbols, which indicate the address space of each output segment in the running domain. You can use import to introduce them during use: | Image $ Ro $ base |: indicates the starting address of the RO segment in the running domain. | Image $ Ro $ limit |: address after the last address of the RO region, that is, the start address of the RW data source. | Image $ RW $ base |: the starting address of the RW zone in Ram, that is, the address specified by rw_base In the compiler. | Image $ Zi $ base |: Start address of the Zi district in Ram | Image $ Zi $ limit |: Address next to the end address of the Zi district in Ram RO base corresponds to | image $ Ro $ base |, RW base corresponds to | image $ RW $ base |, because the Zi segment is included in the RW segment, | image $ RW $ limit | equals to | image $ Zi $ limit |. The following is an example. Assume that Ro base is set to 0x00000000 and the RW base address is 0x30000000. Then, image entry point is available in the options Option, is the entry address of an initial program, set to 0x00000000 (the entry address of the program starts from the code segment (RO ). What we need to do now is to move the RW section to a place starting with 0x30000000 and create an Zi section. First, compare image $ Ro $ limit and image $ RW $ base. If they are equal, the address of RW section under execution view is the same as that of RW section under load view, in this way, you do not need to move the RW section. If there is no difference, you need to move the RW section to its place in the execution view, copy the initial RW data from the ROM | image $ Ro $ limt | to ram | image $ RW $ base | start address, when the target address of the ram side reaches | image $ Zi $ base |, it indicates the end of the RW area and the start of the Zi area. Then, the Zi area is cleared, until the end address is reached | image $ Zi $ limit |. Arm image file and its address ing (2) The sample code is as follows: Import | image $ Ro $ limit | Import | image $ RW $ base | Import | image $ Zi $ base | Import | image $ Zi $ limit | Import main; declare the main () function in the C program Area start, code, readonly; declare the code segment start Entry; identifies the program entry Code32; declare 32-bit arm commands Reset LDR sp, = 0x40003f00 Initialize the running environment of the C program LDR r0, = | image $ Ro $ limit |; obtain the start address of the RW data source. LDR R1, = | image $ RW $ base |; start address of the RW zone in Ram LDR R3, = | image $ Zi $ base |; start address of the Zi area in Ram CMP r0, R1; check whether the address of RW section is equal under load view and execution View Beq loop1; if it is equal, the RW section is not moved, and the Zi scetion is directly created. Loop0; otherwise, copy the RW section to the address specified in execution view. CMP R1, r3 Ldrcc R2, [R0], #4; it copies the section starting from the address in R0 to the section starting from the address in r1 Strcc R2, [R1], #4 BCC loop0 Loop1 LDR R1, = | image $ Zi $ limit |; address at the end of the Zi Section MoV R2, #0; mount the initialization quantity required by the Zi section to R2 Loop2 CMP R3, R1; Establish and initialize the Zi Section Strcc R2, [R3], #4 BCC loop2 B Main; jump to the C program code main () function End Note: ldrcc R2, [R0], #4; read the memory unit data with the address R0 to R2, and then R0 = R0 + 4 CC (less than), eq (equal) is the condition code. After compiling the program, we need to compile and link it. Select the make button in ads1.2 and an errors and warnings dialog box will appear, the compilation and link results are displayed in this column. If there are no errors, you can see the image component sizes at the end of the file, followed by code, RO data, RW data, zi data, debug the number of bytes of each project, and finally there will be a statistical data of them, the number of bytes is based on the user's different programs. Image component sizes Code Ro data RW data Zi data debug 17256 158096 8 184 112580 object totals 1064 299 0 0 796 library totals ========================================================== ======== Code Ro data RW data Zi data debug 18320 158395 8 184 113376 grand totals ========================================================== ======== Total Ro size (code + RO data) 176715 (172.57kb) Total RW size (RW data + Zi data) 192 (0.19kb) Total Rom size (code + RO Data + RW data) 176723 (172.58kb) ========================================================== ======== Code: displays the number of bytes occupied by the Code. RO data shows the number of bytes occupied by read-only data. RW data shows the number of bytes occupied by read/write data. Zi data shows the number of bytes occupied by zero-initialization data. Debug shows how many bytes of debugging data are occupied. The object totals shows the number of bytes occupied by the object generated after the link is linked together. Library totals shows the number of bytes occupied by the library members extracted and added to the image as a single object. Grand totals displays the true size of the image. Grand totals = library totals + object totals The preceding data is used as an example to describe the calculation of several variables: | Image $ Ro $ base | = image entry point = 0x00000000; indicates the starting address for storing program code. | Image $ Ro $ limit | = | image $ Ro $ base | + total Ro size (code + RO data) = 0x0 + 176715 + 1 = 0x0002b24c (because it must meet the multiples of 4, + 1) | Image $ RW $ base | = 0x30000000; specified by RW Base | Image $ RW $ limit | = | image $ RW $ base | + total RW size (RW data + Zi data) = 0x30000000 + 192 = 0x300000c0 | Image $ Zi $ base | = | image $ RW $ base | + RW data = 0x30000000 + 8 = 0x30000008 | Image $ Zi $ limit | = | image $ RW $ limit | 3. Complex address ing In complex cases, for example, when the RO segment is divided into several parts and mapped to multiple locations in the bucket, you need to create a text file called "distributed load description file, notifies the connector to connect a part of the program to an address space in the memory. It should be noted that the definition in the Distributed Loading description file should be based on the memory distribution after system redirection. After the boot program completes the initialization task, the main program should be transferred to ram for running to speed up the system. For example, scatter load mechanism is required to solve the problem of complex memory map. _ Main () and main () are different: After all the system initialization is complete, you need to transfer the program process to the main application, that is, call the main application. One of the simplest cases is: Import main B Main Directly jump from the startup code to the main function entry of the application. Of course, the main function name can be defined by the user. In the arm ads environment, a system-level call mechanism is also provided. Import _ main B _ main _ Main () is a function provided by the compilation system. It initializes the library function and initializes the application execution environment, and automatically jumps to main (). Therefore, the former (_ main) is the library function, and the latter is the main () main function we compile ourselves; Therefore, the B _ main we use is actually to execute the library function, and then the library function calls our main () function, therefore, during single-step debugging, you will see that you must first run a program (actually a library function ), then, go to our own main function (this also indicates that if there is B _ main, there must be a main function; otherwise, the compilation fails ), if we use B Main to access our main function, we can see that it directly enters our own main function during single-step debugging, and no other programs will be seen in the middle; So what are the differences between using B _ main and using B Main to access our main function? If the former is used, a "segment copy" program will be added by the compiler, that is, the domain Conversion Program from loading the domain to executing the domain Conversion Program, and the latter will not have this, therefore, if you want to perform "segment copy", you can only write programs by yourself. After completing the segment copy, you can enter our main function, of course, this main function is not necessarily called Main (). It can start with a nice name. It is different from using the B _ main method. No matter which method is used to enter our program, there must be a "segment copy" program. After the segment copy is finished, you can enter our main program! (By the way, the startup. s file does not have the so-called "segment copy" function, and it will be useless again !) For a Startup Program, "the execution address is the same as the loading address" is not easy to implement: if the execution address is the same as the loading address, you do not need to perform "segment copy ", however, I personally understand that the compiler will also add a "segment copy" Program (if B _ main is used), but it will not be executed because the conditions are not met, "The execution address is the same as the loading address. because the boot program is to burn to non-Easy Loss memory, used for power-on execution, and this program will certainly have RW segments, if RW is placed in non-Easy Loss memory, such as flash, it is difficult to implement the RW function, so it is necessary to move the RW to a memory that can implement the RW function, such as SRAM. therefore, it is not easy to implement "the execution address is the same as the loading address" for the Startup Program. The entry point of the program is at _ main in the C library, at which point, the library code performs the following operations: 1. Copy the non-zero (read-only and read-write) Running region from its load address to the running address. 2. Clear the Zi area. 3. Jump to _ rt_entry. |