I am programming an ARM Cortex-R4 and I have a few binary files that I'd like to execute them from TCRAM, just to see if the increase in performance is good enough.
I know I'd have to write a function to copy the binaries to the RAM (which can be accomplished with the linker script, and knowing the size of the binaries). But how would they run?
Imagine this: The first binary has func1(), func2(), func3() and func4(). I'd copy the entire module to TCRAM and how would I call a function there? I'd have to use a function pointer to that specific function? And what if func4(), calls func2() and func3()? If I'm not mistaken they'd point to the piece of code located in the flash. Does that mean I'd have to re write those funcs? Use entirely function pointers? I've been told that just the linker script is enough to do all of this and I needn't worry about anything, but I still don't understand how it works.
On GCC: Just put the function in the .data section:
__attribute__( ( section(".data") ) )
It will be copied over with the rest of your initialzed variables by the startup code (no need to mess with the linker scipt). You may also need a "long_call" option as well if the function ends up "far away" from the rest of the code after being placed into RAM.
__attribute__( ( long_call, section(".data") ) )
Example:
__attribute__( ( long_call, section(".data") ) ) void ram_foobar (void) { ... }
You may get an compiler warning that can be safely ignored:
Warning: ignoring changed section attributes for .data
You have two options.
Copy them as you suggest, compile with pc relative.
Use a linker file with a different load/run address.
A simple copy will only work if the routines do not use any absolute addresses. It maybe fine if they do use the absolute address as I guess you are going to leave a copy in standard RAM. However, this may not get the full benefit of the TCM.
With a linker script, you can specify a different LOAD and RUN locations.
sections {
.text { *(.text); } >FLASH
.tcm {
*(.tcm);
} >TCM_MEM AT>FLASH
.data { *(.data); } > RAM
.bss : NOLOAD { *(.bss); } > RAM
}
Note especially AT>FLASH.
See also: gnu linker map file... and many more on stackoverflow. The Gnu Ld manual has information on LMA sections (LOAD address). Your LMA would be flash, but the VMA (RUN address) would be TCM. The manual link above also shows how to copy. The RAM, FLASH, and TCM_MEM are defined with ld MEMORY information, depending on the addresses are for your board. All of this will be documented in a MAP file. Be sure to generate a MAP file and examine the addresses to double check your ld script.
The 2nd case also requires a copy (at start-up or at least before the first TCM function use). However, the compiler can use absolute addresses and they will be in the TCM memory. Also any function within the main DRAM can call the TCM function directly. With the first case, you must use function pointers to call the TCM code. If you wish global variables to be placed in this memory, you can use attributes to put them in different sections and use gnu ld to place them appropriately. I think there is ITCM and DTCM? So maybe this doesn't apply for you, or you need two sections.
The linker script is more generic and will work best if you put complicated functionality in the TCM. Just using -fpic, etc and copying may get things working quickly, especially if you only have a single pure function.
Nowadays (then-a-days as well?) you can just use the macro __RAM_FUNC, __RAMFUNC_EXT(bank, name) or __RAMFUNC(bank)
Related
I am working on a project which contains of subset of code which needs to be validated from flash at runtime with a CRC value. This code is placed into its own section of flash using the linker and during build the CRC value is calculated and injected into the appropriate area of memory. Then at runtime the flash is read and CRCed and compared to the stored value. This is all working correctly and as intended.
The code which is placed into this special section of flash is considered critical which is why it needs to be verified periodically as correct at runtime. The CRC value is also supposed to be used to validate that no changes were made to the critical section from version to version. This is what is not working as expected.
When the changes to non-critical sections of code are made (for example things placed into the normal .text region of flash) there are small differences in the critical code. Upon examining the changes it appears that most, perhaps all, of the changes are due to external function/variable references which are not in the critical code section of flash. This of course makes sense because the linker will be inserting the calls to other functions wherever they might get placed in flash which of course can change.
Is it possible to force the linker to make references to external functions/variables static in this section of flash? I was thinking this could be accomplished with some kind of lookup table which contained virtual memory/function addresses and then actual memory/function addresses and the critical code section would only reference the virtual addresses?
You don't say what CPU you are using, but suppose you want to call routine do_stuff from your critical section, with signature int do_stuff(int a, intb). Then you need a header in your critical section:
int tramp_do_stuff(int a, int b);
and an assembly file with a trampoline for each function in your normal section:
.org 7ffff00H ;; however you specify a fixed address in your asm
_tramp_do_stuff: ;; this address is fixed
JMP do_stuff ;; This address gets set by linker
_tramp_next_trampoline:
I want to build a library which is relocatable (ie. nothing other than local variables. I also want to force the location of the library to be at a fixed location in memory. I think this has to be done in the makefile, but I am confused as to what I have to do to force the library to be loaded at a fixed location. This is using mb-gcc.
The reason I need this is I want to write a loader where I dont want to clobber over the code that is actually doing the copy of the other program. So I want the program that is doing the copying to be located somewhere else at a location that is not being used (ie. ddr).
If I have all the functions that do the compiled into a library, what special makefile arguments do I need to force this to be loaded at location 0x80000000 for example.
Any help would be greatly appreciated. Thanks in advance.
You write a linker script, and tell the compiler/linker to use it by using the -T script.ld option (to gcc and/or ld, depending on how you build your firmware files).
In your library C source files, you can use the __attribute__((section ("name"))) syntax to put your functions and variables into a specific section. The linker script can then decide where to put each section -- often at a fixed address for these kinds of devices. (You'll often see macro declarations like #define FIRMWARE __attribute__((section(".text.firmware"))) or similar, to make the code easier to read and understand.)
If you create a separate firmware file just for your library, then you don't need to add the attributes to your code, just write the linker script to put the .text (executable code), .rodata (read-only constants), and .bss (uninitialized variables) sections at suitable addresses.
A web search for microblaze "linker script" finds some useful examples, and even more guides. Some of them must be suitable for your tools.
I've seen code like below in a project:
extern void my_main(void) __attribute__ ((__noreturn__, asection(".main","f=ax")));
What does this do?
The project does not have a direct main() function in it. Does the above code indicate to the compiler that my_main() should be treated as main()?
Also, what does the .main memory section indicate?
What the above declaration basically does is declare an extern function called my_main() with no arguments.
The __attribute__ section is a GNU/LLVM attribute syntax. Attributes are basically pragmas that describe some non-standard or extended feature of the function in question - in this case, my_main().
There are two attributes applied to my_main().
__noreturn__ (search for noreturn) indicates that the function will never return.
This is different from returning void - in void-type functions, calls to the function still return at some point, even without a value. This means execution will jump/return back to the caller.
In noreturn (a.k.a. _noreturn or __noreturn__) functions, this indicates that, among other things, calls to this function shouldn't add the return address to the stack, as the function itself will either exit before execution returns, or will long jump to another point in execution.
It is also used in places where adding the return address to the stack will disrupt the stack in a way that interferes with the called function (though this is rare and I've only ever seen it used for this reason once).
The second attribute, asection(".main","f=ax"), is a little more vague. I can't seem to find specific documentation for it, but it seems more or less pretty straightforward.
What it appears to be doing is specifying a linker section as well as what appears to be a unix filemode specifying that the resulting binary is executable, though I could be wrong.
When you write native code, all functionality is placed into appropriate sections of the target binary format (e.g. ELF, Mach-O, PE, etc.) The most common sections are .text, .rodata, and .data.
However, when invoking ld, the GCC linker, you can specify a linker script to specify exactly how you want the target binary to be constructed.
This includes sections, sizes, and even the object files you want to use to make the file, specifying where they should go and their size limits.
One common misconception is that you never use ld. This isn't the case; when you run gcc or g++ or the clang-family of compilers without the -c flag, you inadvertently invoke ld with a default linker script used to link your binaries.
Linker scripts are important especially for embedded hardware where ROM must be built to memory specification.
So back to your line of code: it places my_func() into an arbitrary section called .main. That's all it does. Ultimately, somewhere in your project, there is a linker script that specifies how .main is used and where it goes.
I would imagine the goal of this code was to place my_main() at an exact address in the target binary/executable, so whatever is using it knows the exact location of that function (asection(".main")) and can use it as an entry point (__noreturn__).
I am using gcc to compile some code for an ARM Cortex-M4F microcontroller. My application uses a large collection of data that I have conveniently written into a C file: large arrays of ints and floats, circular linked lists pointing to those various arrays, various structs, that sort of thing.
When I compile this it adds up to about 500K of data, plus a few hundred K for the actual application. gcc is putting all this data conveniently into the .data section; ld then tries to build the elf putting the .data section into RAM and .text (code) section into FLASH. The mcu I am using doesn't have 500K of RAM so it cannot build the ELF, but it does have 1M of FLASH. I tried changing my linker script so that both .data and .text are put into FLASH which "worked" but there are some other bit of code that expect its data to go into RAM, so ultimately execution failed; I can't make that sweeping change.
What I need is to tell gcc to put every single object in this C file into the .text section so it can go into FLASH with the rest of the non-mutable stuff, or at least some other section which I can then instruct my linker script what to do with so that it doesn't interfere with existing blobs that have no problem fitting in RAM. I don't know how to do that. Here is a very slimmed down example of what I have
/* data.c */
static char* option_array_0_0[] =
{
"O=0.40",
"K=FOO",
"JAR=JAR",
};
static int width_array_0_0[] =
{
0,
1,
1,
};
Window window_array_0[] =
{
{
option_array,
width_array,
},
};
/* main.c */
extern Window window_array_0[];
int main()
{
/* Do stuff */
}
The stuff in data.c, window_array_0 and everything (or most everything, maybe the string arrays are going to .text?) it links to, is being put in .data which my linker script puts into RAM. I want it all in a different section which I can then put into FLASH. There are thousands of these types of arrays in there, plus hundreds of structs and dozens of other bits of information. Is this possible to change? As a test I replaced my "window_array_0" with a char[500000] of random data and that compiled without complaint so I assume it put it all into .text (as would be expected), I just don't know how to make it do so for arbitrary objects.
Thanks for your help.
As other commenters pointed, 'static const' items usually end up in .rodata section which is likely to be placed right next to .text in potentially read-only memory. The caveat is that it may or may not be true in your case as that is specific to particular target and may be changed by particular build process (i.e. linker options, specific section specified via __attribute__((section("name"))) in C code, linker script, binaries tweaked after build with various binutils, etc).
If you need to have precise control over in-memory layout and you know what you're doing, you can use LD script to do it. Among other things it will let you specify that .rodata from file data.o should be placed just before/after .text from all other .o files linked into the executable.
You can use arm-<your toolchain variant>-ld -verbose to dump default linker script and use it as a starting point for tweaking.
Most compilers/linkers, if you declare a variable as static const, it will place it in the text section instead of data. Obviously, these must be preinitialized and not modified at run-time, but that's the only way it makes sense to go in flash.
Somewhere in the code (.text section) put like a sample:
__attribute__((section(".text")))
const int test[0x0A] = {0,0,0,0,0,0,0,0,0,0};
or without const if you want a variable to change:
__attribute__((section(".text")))
int test[0x0A] = {0,0,0,0,0,0,0,0,0,0};
Then try changing it:
test[0] = 0xffffffff;
This works on my Linux 32 intel machine.
IIRC, code in flash is usually required to be ROPI (read only position independent). So option_array_0_0 and width_array_0_0 would need const qualifiers (read only). However:
Window window_array_0[] =
{
{
option_array,
width_array,
},
};
needs to be changed somehow (I'm assuming option_array and width_array are indeed arrays). That makes window_array_0 not position independent.
All non-trivial embedded projects shall have a linker script. It defines where different symbols (function, global variables, debug symbols, ...) shall be placed in memory. Here is some tutorial about gcc linker script.
forcing all data to be placed in one section might not be the best solution!
NOTE: Since these arrays are NOT constants, it doesn't make sense to store them in data section! because this means you will end up over-writing code section by you code (which is PRETTY dangerous). Either make them const or create a no-init section which is not initialized by the loader, and you initialize it on reset.
Is it possible to RUN 2 different C programs(ie 2 main()), stored in Flash(micro controller), one at a time?
I have a bootloader code which is a separate program and resides in separate protected section of ROM. Then I have my application program which resides in separate ROM section. Although, residing in memory is not an issue, but how will linker interpret this? How can I switch between 2 programs. Is this possible?
For example:
Once I am done with bootloader, I can make it jump to Application function, but how will linker know this function?
Just to add, I am using Freescale HCS08 series and IDE is Codewarrior.
Further, here are the sequence of steps:
I load a Bootloader code in ROM. Then this bootloader code is required to load my application code. And then my application code should take over.
Bootloader Code:
Program Application Area ROM
Start Application Program
Application Code:
Check if to run Bootloader code or application itself.
Main is just a function. You may rename it and write another main which call either of them.
If you do not want rename main in the source you may mangle its name by define or compiler key:
cc -Dmain=main1 ...
(for first program), and
cc -Dmain=main2 ...
(for the second). Selector main:
int main(void) {
if(x) return main1();
else return main2();
}
Then link all together and download to your controller.
But there's problem with ISR's: you cannot assign two routines to single irq vector. If vectors are hardcoded to some flash location (like in most 8-bit controllers) you cannot switch ISR's. You will have to write ISR wrapper, recognizing which program is run and calling appropriate ISR.
UPD
Second issue is that statically linked variables from first and second program will be in RAM simultaneously while only one set of them is used. This may exhaust RAM (small amount of which often exists in microcontroller) too early.
UPD2
Oh, now I really understand. If you want to link and download them separately, you should deal with linker maps. In this case same symbol names (such as many main's) s not an issue. In linker map you should define known entry point [set it to absolute address], from which either application code starts. Startup code (commonly it is assemble code) should be linked from this address. From selector you should decide and jump to defined location directly. (Do this only for bootloader if your app is also a selector).
Entry point provided by linker may be accessible by program as extern function:
int app2_start(void);
{
.... /* condition check */
app2_start(); /* this symbol defined in linker map, not in any source */
}
But this is not the address of it's main(), because C RTL have do make many initialisations (stack, initialised variables, heap, IO, etc.) before main() can start.
There's more common way that the bootloader decides, should it run itself or application, because if application code fails, boodloader may became inaccessible.
The way I've seen this done is to stick the entry point into a header for the application. Then have the boot loader pull that entry point out and jump to it with an appropriate inline assembly instruction. You may need a linker script to get the entry point itself from the application. Gnu ld uses ENTRY.