Hi,
In order to introduce my issue, my goal is to get 2 similar projects, one compiled by Arm Compiler for Embedded 6 and the other by GCC, both on a FVP Cortex R-52 target.
I chose to build the project on the example available when installing Arm Development Studio named startup_Cortex-R52.
Concerning the Arm Compiler part I have no issues, project works fine as I did not change anything. So I tried to build my second project, compiled by GCC based on the startup_Cortex-R52 example.
I added the GCC 10.3.1 toolchain to Arm Developement Studio and choosed this toolchain in the Tool Chain Editor of my project. I have also set up my project by giving these options in project properties for both GCC Compiler and Assembler : -mcpu=cortex-r52 -mfpu=neon-fp-armv8 -mfloat-abi=hard
Errors occur when I try to build the project and specially in the startup.s file are related to Assembler messages :
I am wondering why I faced this issues as the target is the same and Assembler language too.
If someone can help me to resolve this issue I would be grateful.
Regards, Enzo
Hi EnzoIt looks like you are making good progress - well done!If you have placed gcc.ld at the root of the project, then use "-T../gcc.ld". If not, then insert some other project-relative or absolute path.Hope this helpsStephen
Hi Stephen
Thanks for your answer. I am currently programming my gcc.ld file based on the scatter file for the R52 example. The scatter file is the following :
I notice that there is no memory left between each symbol so it means that i am not supposed to have any Sections between .vectors and .data in my linker script (gcc.ld).
I am wondering where should I put all sections in the gcc.ld (A9x4) between .vectors and .data in my gcc.ld example.
i try to develop my gcc.ld this way (following the A9x4 example) but I am probably missing something.
/* Linker script to place sections and symbol values. * It references following symbols, which must be defined in code: * Vectors : Entry point * * It defines following symbols, which code can use without definition: * __code_start * __exidx_start * __exidx_end * __data_start * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __bss_start__ * __bss_end__ * __end__ * __stack * __irq_stack * __stack * __pagetable_start * ENTRY(Vectors) */ ENTRY(Start) SECTIONS { .vectors 0x0: { __code_start = .; KEEP(*(VECTORS)) . = . + 0x8000; __code_end = .; } .init : { KEEP (*(SORT_NONE(.init))) } .text : { *(.text*) } .fini : { KEEP (*(SORT_NONE(.fini))) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .eh_frame : { KEEP (*(.eh_frame)) } .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array )) PROVIDE_HIDDEN (__init_array_end = .); } .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array )) PROVIDE_HIDDEN (__fini_array_end = .); } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } /* Associate DATA symbol */ .data 0x8000: /*.data : */ { __data_start = . ; . = . + 0x4000; __data_end = . ; } .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; } /* Associate ARM_LIB_HEAP symbol */ .heap 0xC000 (NOLOAD): { __heap = .; . = ALIGN(64); . = . + 0x1000; } /* Associate ARM_LIB_STACK symbol */ .stack (NOLOAD): { . = ALIGN(64); . = . + 4 * 0x4000; __stack = .; } }
But obviously I have overlap issues as there is no memory available for others sections between .vectors and .data
I am wondering if my linker script is similar to the initial scatter file and how to manage the location of others sections.
Thanks again for your help Stephen
Enzo
Hi EnzoIn the scatter file for startup_Cortex-R52, the last parameter 0x8000 in the execution region "CODE +0 0x8000" is an optional maximum length that armlink can use to warn about region overflows, so in your .vectors region you don't need the line: . = . + 0x8000;Also, you'll need to move __code_end = .;to after all the code, i.e. to between the end of .jcr and the start of .data.If GCC is generating larger code than Arm Compiler, causing overflows, you might need to push the start of the .data region to a higher address, e.g.change .data 0x8000:to e.g. .data 0x9000:For the stack, the line in startup_Cortex-A9_GCC gcc.ld: . = . + 4 * 0x4000;was used to represent stack space for each of the 4 cores.If your system has only a single core, you won't need the "4 *"Hope this helps,Stephen
Hi Stephen,
You are right GCC is generating larger code than Arm Compiler. I add the command "-Xlinker -Map=output.map" which help me to see the memory allocation.
Finally my gcc.ld looks like this :
/* Linker script to place sections and symbol values. * It references following symbols, which must be defined in code: * Vectors : Entry point * * It defines following symbols, which code can use without definition: * __code_start * __exidx_start * __exidx_end * __data_start * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __bss_start__ * __bss_end__ * __end__ * __stack * __irq_stack * __stack * __pagetable_start * ENTRY(Vectors) */ ENTRY(Start) SECTIONS { .vectors 0x0: { __code_start = .; KEEP(*(VECTORS)) } .init : { KEEP (*(SORT_NONE(.init))) } .text : { *(.text*) } .fini : { KEEP (*(SORT_NONE(.fini))) } .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } .eh_frame : { KEEP (*(.eh_frame)) } .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array )) PROVIDE_HIDDEN (__init_array_end = .); } .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array )) PROVIDE_HIDDEN (__fini_array_end = .); } .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } .jcr : { KEEP (*(.jcr)) } .endd : { __code_end = .; } /* Associate DATA symbol */ .data 0xC000: /*.data : */ { __data_start = . ; . = . + 0x4000; __data_end = . ; } .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; _end = __bss_end__; end = _end; } /* Associate ARM_LIB_HEAP symbol */ .heap 0x12000 (NOLOAD): { __heap = .; . = ALIGN(64); . = . + 0x1000; } /* Associate ARM_LIB_STACK symbol */ .stack (NOLOAD): { . = ALIGN(64); . = . + 4 * 0x4000; __stack = .; } }
If it can help someone, you can mention that I add these lines to .bss to resolve an error and change .data and .heap starting addresses memory allocation :
_end = __bss_end__; end = _end;
Last errors are the following :
I know that those issues could be resolved by adding the flag "-specs=nosys.specs" but it will disable the semihosting whereas I want to use it to print the execution time and other stuff. Is there any other solution to resolved these errors ?
PS : I also tried the -specs=rdimon.specs but it led to this error which I am unable to resolve
../arm-none-eabi/lib/thumb/v7+fp/hard/rdimon-crt0.o: in function `_mainCRTStartup': (.text+0x15c): undefined reference to `__end__'
Thanks again,
Hi EnzoYou should link with --specs=rdimon.specs, then add the necessary "__end__" symbol into your gcc.ld to mark the end of the .bss region.Hope you will now get a successful link :)Stephen
Thank you so much, now my linking is working well and i could build the project without errors.
When I try to debug my project I am facing an error, I think that i never reach the main of my program. I set the debut point to entry point to understand the process. My program correctly execute instructions in the startup.S file that I have created. The issue occurs after the _start symbol (at the end of my startup file) :
//---------------------------------------------------------------- // Branch to C library init // Leaving the MPU and caches disabled until after scatter loading. //---------------------------------------------------------------- cpu0: .global _start B _start // .size Reset_Handler, . - Reset_Handler
In the disassembly window, Its seems that my program is stuck after executing these line in the memset function :
Which led to the EL1_Abort_Addr which I think I should not be redirected to :
And then I am blocked in Evaluating step in the progress.
I don't know what can led to this issue, do you think it's a memory address assignment issue ?
Thanks again.
Hi EnzoI suspect this is a problem with the stack. As a quick experiment, try making the stack larger. For a more detailed analysis, you will need to step through the startup code to see where the stack pointer is changing (watch SP in the Registers view). The original startup code for AC6 (in startup.s) sets up stack areas for all modes (ABT, IRQ, FIQ, SVC). I believe the GCC startup code (within crt1.o) does the same again, so stack space is being unnecessarily wasted. You can probably remove that unneeded code from startup.s. I hope this helps you makes some further progress with your debugging.Stephen
As you suggested I removes the unneeded code in startup.s which sets up stack areas for all modes (ABT, IRQ, FIQ, SVC).
//---------------------------------------------------------------- // Initialize Stacks using Linker symbol from scatter file. // ABT, IRQ, FIQ, UNDEF size = STACKSIZE, SVC the rest. // Stacks must be 8 byte aligned. //---------------------------------------------------------------- #define STACKSIZE 512 // // Setup the stack(s) for this CPU // the scatter file allocates 2^14 bytes per stack // MRC p15, 0, r1, c0, c0, 5 // Read CPU ID register AND r1, r1, #0x03 // Mask off, leaving the CPU ID field LDR r0, =__stack SUB r0, r0, r1, lsl #14 /* CPS #Mode_ABT MOV SP, r0 CPS #Mode_IRQ SUB r0, r0, #STACKSIZE MOV SP, r0 CPS #Mode_FIQ SUB r0, r0, #STACKSIZE MOV SP, r0 CPS #Mode_SVC SUB r0, r0, #STACKSIZE MOV SP, r0 */
I debugged my program step by step and I didn't mention any change concerning SP register during the execution of startup.S.
In fact, in the Disassembly window when program enter in the _stack_init symbol SP register address is moving to the value 0xFFFF0000 or my stack is define between 0x00013000 and 0x00023000 (see the following map file). I am wondering how can I change this assignment (how to access to _stack_init).
Hi EnzoI suspect you have not launched the FVP model with "-C cluster0.cpu0.semihosting-stack_base=0".
When the FVP model is launched, some default values for stack/heap base/limit are applied.You can see the defaults by launching the FVP model on the command-line with e.g.:C:\Program Files\Arm\Development Studio 2022.1\bin>FVP_BaseR_Cortex-R52x1.exe --list-params | find "semihosting-":cluster0.cpu0.semihosting-heap_base=0 # (int , init-time) default = '0x0' : Virtual address of heap base.cluster0.cpu0.semihosting-heap_limit=4278190080 # (int , init-time) default = '0xff000000' : Virtual address of top of heap.cluster0.cpu0.semihosting-stack_base=4294901760 # (int , init-time) default = '0xffff0000' : Virtual address of base of descending stack.cluster0.cpu0.semihosting-stack_limit=4278190080 # (int , init-time) default = '0xff000000' : Virtual address of stack limit.:That explains why you are seeing '0xffff0000' being obtained by the semihosting call at the beginning of _start:MOVS r0,#0x16ADR r1,{pc}+0xc2 ; 0x1F4SVC #0xabThe use of "0" for stack_base and heap_base have particular purposes. For stack_base=0, it doesn't mean put the stack at 0x0. At run-time, if the C library startup code gets a stack_base of 0 from that semihosting call, it replaces the 0 with a stack_base address derived from the gcc.ld script by the linker at link-time.You can see this effect if you step through the code in _start.Stephen
C:\Program Files\Arm\Development Studio 2022.1\bin>FVP_BaseR_Cortex-R52x1.exe --list-params | find "semihosting-"
:
cluster0.cpu0.semihosting-heap_base=0 # (int , init-time) default = '0x0' : Virtual address of heap base.
cluster0.cpu0.semihosting-heap_limit=4278190080 # (int , init-time) default = '0xff000000' : Virtual address of top of heap.
cluster0.cpu0.semihosting-stack_base=4294901760 # (int , init-time) default = '0xffff0000' : Virtual address of base of descending stack.
cluster0.cpu0.semihosting-stack_limit=4278190080 # (int , init-time) default = '0xff000000' : Virtual address of stack limit.
Thanks to your answer I understood the meaning of the "0" value for stack_base and I added the parameter you suggested. Now my memory allocation is correct.
Therefore, when I step through my code especially while looking at the Disassembly window I am correctly accessing to my main function but program stopped when I reach the first call of printf (enable_mpu() works fine).
I am wondering what could blocked there.
Thanks
Hi again EnzoYou don't say what happened when your program stopped, for example, was it hung in a loop, or had an unhandled exception occurred? My guess is that there is a problem with the heap (which printf uses). Maybe the stack has grown down too far and collided/corrupted the heap? As an experiment, did you try making your stack larger earlier? You'll need to debug your code to find out what caused the problem. As a starting point, I suggest you enable capture of the history of instruction execution ("trace"), and enable the trapping of exceptions:1) Disconnect the Debugger from the FVP2) Run > Debug Configurations..., select your debug launch config3) Click on the "DTSL Options..." Edit button4) In the Trace Buffer tab, select Model Trace. In the Core Trace tab, select the processor you want to trace, then OK5) In Debug Configurations, click Debug to re-start a debug session. Don't run your code yet!6) Open the Trace view with Window > Show view > Trace7) Set breakpoints on all the EL1_xxx_Handlers. These are just dummy "branch-to-self" handlers that do nothing.Click Debug to start a debug session. You'll then be able to see in the Trace view where and why your program is stopping, for example, if an invalid address is being accessed.Hope this helps you to debug your codeStephen
Hi Stephen thanks for your answer,
Thanks to the Trace windows that you helped me to set up, I can see what is going wrong.
So, when I reach the printf function in my main.c and see associated instruction execution I can see that the exception occurs in the puts function and it seems to be a HANDLE_DATA_ABORT (16) Exception (by the way I do not know what 16 mean there).
As you suggested I made my stack bigger :
Unless I'm wrong, It seems that the stack is not the issue as the SP value is included in my stack range when the Exception occurs :
And thanks to your tips on breakpoints I noticed that it's redirect to EL1_Abort_Addr which is consistent with the Exception : HANDLE_DATA_ABORT.
I thought it was a heap issue as printf uses heap but I tried to delete the starting address parameter (0x12000) and also to extend heap size independently but the exception occurs as well.
Maybe I am missing something as I am a beginner on Arm DS.
Thanks again for your help Stephen, it really helps me to go through my project configuration.
Hi again EnzoA data abort will occur if an attempt is made to read/write a memory location, but there is no memory at that address, or the MPU has blocked access to that address.The trace view shows the data abort is caused by the "LDR r0,[r3,#0]" instruction at 0xCF6, which is trying to load a 32-bit word from the address held in r3. Set a breakpoint on that instruction and run to it. Check the value of r3 in the Registers view. Is it a sensible address? If so, perhaps the MPU is not being programmed correctly, and access to that memory is accidentally being blocked. Try temporarily disabling the MPU (either comment out the call to enable_mpu(), or use the Registers view to clear the M bit in the System Control register before executing the LDR).I suspect the problem might be related to the placement of __data_end in your gcc.ld. In startup.S, the MPU config for "Region 1 - Data" should cover both the RW (.data) _and_ ZI (.bss) regions. I suggest you check that the memory regions programmed in the MPU config code and the corresponding base/limit symbols in your gcc.ld are as expected.Hope this helpsStephen
As you suggested I moved my __data_end to the last line of .bss in the linker script gcc.ld.
I had another DATA_ABORT issue because the address was already used.
As we can see in the map file :
So I shifted all my symbols after that line by 0x04 :
My map file finally looks like this :
And this works,both printf function and my configuration are working well. I am just wondering if there is a cleaner way to do the shifting ?
Thanks for everything Stephen, I am so glad my configuration with GCC is finally working. I hope it will be useful for other users.
Hi EnzoGlad to hear that your project is now working :)Stephen
EnzoL I am trying to create this exact project using GCC! Would you be able to provide it as a .zip file here for me?
I would greatly appreciate it!
Chris