Author Topic: GCC ARM32 32F417 how to call or jump to a specific address?  (Read 2395 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Of course, the "answers" are all over the internet, but none of them compile, or (if they compile) none work.

I have what is basically an overlay at FLASH base+32k ie.. 0x08008000 and need to jump to that address.

The address is actually a symbol from the linkfile called FLASH_APP.

I see examples like

   ldr  r3, =JMPADDR
   bx   r3

and have been trying various forms of stuff like asm volatile("bx %0" : : "r" (0x08008000)); but nothing works. I spent decades coding in asm so this should be simple :)

I am using GCC v10. Many thanks for any tips.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #1 on: June 13, 2022, 04:33:32 pm »
.
« Last Edit: August 19, 2022, 05:35:54 pm by emece67 »
 
The following users thanked this post: edavid

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #2 on: June 13, 2022, 05:08:21 pm »
That doesn't appear to go to a fixed absolute address:

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #3 on: June 13, 2022, 05:20:29 pm »
.
« Last Edit: August 19, 2022, 05:36:03 pm by emece67 »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14445
  • Country: fr
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #4 on: June 13, 2022, 05:50:15 pm »
If you're using GCC, you can also use computed gotos: http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
Of course, this is not standard C, and if the pointer points to an absolute address rather than "the address of a label", the behavior *may* be undefined. Not sure.
But it's just a "fun" feature to know, and it seems to "work":

https://godbolt.org/z/bfdMMaczv
 

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3690
  • Country: nl
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #5 on: June 13, 2022, 05:51:33 pm »
Try this

Code: [Select]
  //Start the main program 
  unsigned int address = 0x80000000;

  __asm__ __volatile__ ("mov pc, %0\n" :"=r"(address):"0"(address));

I have used this in the FNIRSI-1013D bootloader.

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #6 on: June 13, 2022, 06:03:18 pm »
Pretty typical stuff from bootloaders:
Code: [Select]
  asm("bx %0"::"r" (0x08008000));
No need for extra stuff, let the compiler figure it out. GCC inline assembly is incredibly flexible and powerful.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #7 on: June 13, 2022, 06:35:48 pm »
Unfortunately none of this works.

This C code works, and has been for ages. The module main.o is located (in the linkfile) to FLASH_APP which is 0x8008000, and this does it





and main() is this stub



And I could just do the above, because if FLASH_APP changes then it will all still work.

But if I use asm



R3 has the right value



but then it bombs, and same if I use 0x8008001.

I saw C generates bl whereas the asm used bx, but bl produces a compiler error

« Last Edit: June 13, 2022, 06:37:24 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #8 on: June 13, 2022, 06:40:50 pm »
You have to use the value with 1 in LSB, of course for the "bx" instruction.  It absolutely works, so you are doing something wrong. So, what do you mean by "bombs".  What actually happens to the PC?

There is no "bl" instruction that takes a register as an argument, only immediate value. But either one should work if your offset is constant.

Do you have raw code or a standard vector table at 0x08008000? If later, then the approach is entirely different.

If you have a typical application linked at that address, then the code to run it would be something like this:

Code: [Select]
static void run_application(void)
{
  uint32_t msp = *(uint32_t *)(0x08008000);
  uint32_t reset_vector = *(uint32_t *)(0x08008004);

  __set_MSP(msp);
  asm("bx %0"::"r" (reset_vector));
}
« Last Edit: June 13, 2022, 06:45:51 pm by ataradov »
Alex
 

Offline mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13736
  • Country: gb
    • Mike's Electric Stuff
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #9 on: June 13, 2022, 06:42:56 pm »
I'm no C expert but i think you can do this by casting and function pointers.

This is what I use in PIC32 (MIPS) bootloaders, copied from Microchip's sample code - I would imagine ARM may be similar.


void JumpToApp(void) {
  void (*fptr)(void);
    fptr = (void (*)(void))USER_APP_RESET_ADDRESS;
    fptr();
}
 
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #10 on: June 13, 2022, 06:47:38 pm »
What seems to be happening is that both 8008000 and 8008001 does the same job, but the code I am jumping to is getting removed by the compiler because it is no longer referenced ;)

Not sure how to stop that, other than put in some spurious code.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #11 on: June 13, 2022, 06:50:33 pm »
How exactly are you placing it there? You really need to be more specific, we can't guess what you are doing.

And if it comes from the same project, then why not just call it directly? It will be used in that case, and you don't need to do anything else.

Can you explain what you are actually trying to achieve? You seem to be over complicating things, as usual.
« Last Edit: June 13, 2022, 06:52:20 pm by ataradov »
Alex
 
The following users thanked this post: langwadt, newbrain

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #12 on: June 13, 2022, 07:29:52 pm »
I am trying to keep explanations simple because I learnt that any post longer than x lines never gets a reply ;) The internet is full of desperate people posting huge amount of code and 99% never get a reply and disappear. The result is a lot of google hits and a load of clickbait.

The code I am trying to jump to is like this in the linkfile:



FLASH_APP is 0x8008000.

I noted that if I use the asm jump form, the stub disappears and the jump goes to the vector table instead which follows it. This is despite the KEEP directives you can see there.

Yes it is the same project but the code after base+32k is customer-replaceable. So it is a kind of an overlay.

I can go back to my old method but the same disappearing-code issue will surface when compiling the overlay... nothing will be referencing its base so it will get optimised away too.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #13 on: June 13, 2022, 08:04:26 pm »
If it is user-replaceable, why not keep it in the separate project? Once you want to replace it, you will have to separate the code anyway. And then the whole thing just becomes a standard bootloader.

How are you checking that it is eliminated? How are you preparing the loadable image?  Are you sure your programming tools can handle multiple sections like this?

I have no idea about linker syntax for individual files, to me this always seemed like an avoidable and unnecessary hack. You may need to add KEEPs around other statements there. But again, double check that your tools can deal with the resulting multi-section files.
« Last Edit: June 13, 2022, 08:08:45 pm by ataradov »
Alex
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6239
  • Country: fi
    • My home page and email address
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #14 on: June 13, 2022, 08:23:39 pm »
What seems to be happening is that both 8008000 and 8008001 does the same job, but the code I am jumping to is getting removed by the compiler because it is no longer referenced ;)

Not sure how to stop that, other than put in some spurious code.
Since you are using GCC, mark the target function(s) __attribute__((used)).  In other words:
    __attribute__((used))
    return_type function_name(argument_list...) { ... }

Edited to add:  Since it is intended to be user-replaceable and never returns and doesn't take any arguments, you can do e.g.
    __attribute__((used, weak, noreturn)) void function_name(void) { for ( ; ; ) /* nothing */; }

Any other definition of function_name will override that "default" implementation.
« Last Edit: June 13, 2022, 08:28:51 pm by Nominal Animal »
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #15 on: June 13, 2022, 08:24:49 pm »
It is eliminated, probably by the linker but I am not sure. I can see it is eliminated because at 0x8008000 I can see the next module (a vector table, which is 0x200-aligned as you know).

I am successfully doing the jump now, using some code based on code  used on the RAM-resident boot loader which I developed about a year ago, with much help here:



and with this I do indeed get a jump to 0x8008000



Now I need to work out how to prevent that stub from getting eliminated. Tried all kinds of stuff but none works. The KEEP attribute in the linkfile does nothing. Problem is that there are so many different versions of these tools

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #16 on: June 13, 2022, 08:30:00 pm »
I don't get it. Your base project has main() too? Why not name this entry_main() and just call entry_main() from the regular code? Then in the linker place entry_main at whatever offset you want.

You are really making it more complicated than it has to be.

But again, what are you going to do then it is time to extract the user section? You'd need to have a way to compiler and link it separate from the main project, or some way to extract it. But if you are building all the code at the same time anyway, why does it matter where it is located?

Also, why even have this dummy main()? What you are doing is literally what bootloaders do. Place the user vector table at the offset 0x08008000 and use the code I previously provided.
« Last Edit: June 13, 2022, 08:34:20 pm by ataradov »
Alex
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14445
  • Country: fr
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #17 on: June 13, 2022, 08:30:17 pm »
GCC might prune unused static functions, but not non-static ones.
LD will not prune the code for unused functions either on its own.

Unless you instruct them to do so. Typically using the '-ffunction-sections' option for GCC and '--gc-sections' for the linker.
If those options are set, then I'm not sure there is any other way of bypassing this pruning than what Nominal just suggested above.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #18 on: June 13, 2022, 08:40:36 pm »
The boot block, 0x8008000-0x8007FFF, gets entered via the standard vector table. It does various stuff and jumps (or calls; it doesn't matter) the replaceable module at 0x8008000.

Thus far, for the year+ I've been working on this, I have been compiling the two parts together. But in the future somebody will have a Cube installation which generates only the replaceable module, origin 0x8008000. And he will have a main() because he, like all C coders, expect to have a main() :)

This is not rocket science...

And it is possible that the main() in this second development environment will not get optimised away. Partly because a compiler which removes main() is going to cause a load of problems ;) and partly because, on an ARM32, main() is pointed to by a jump in the vector table, in the startup.s file.

The problem is that in my current project this whole stub is getting removed.

Why is it a stub? So I can use the linkfile to place it at 0x8008000, while making sure there is no .h file #included at the start which just happens to contain some code. Only a simple clean stub achieves this.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #19 on: June 13, 2022, 08:46:15 pm »
Yes, this is not a rocket science. As I said, what you are doing is the standard way all bootloaders work. Just link the user vector table at the beginning of the 0x8000 block and jump there by reading the SP value and reset vector. Reset vector would be your entry point. If you don't need initialization, you can skip it in the reset handler and just jump to the application main().

You are not doing anything special, just a really bad way to implement a bootloader.

But you also have to think though how all this works with the memory allocation. If you are building this as one project, then SRAM occupied by the boot code would not be available to the user code. If you build them separately, then you need to do exactly what I described.
« Last Edit: June 13, 2022, 08:48:57 pm by ataradov »
Alex
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6239
  • Country: fi
    • My home page and email address
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #20 on: June 13, 2022, 09:02:08 pm »
It is eliminated, probably by the linker but I am not sure.
Be sure, by checking the object (.o) file, via e.g. objdump -t name.o or readelf -s name.o.  They list even local objects (those without external linkage).

If they are missing from the intermediate object file, then it is the compiler that never emitted the code for the function, and __attribute__((used)) should fix it.  If they are only missing from the final object file (before being converted to hex format), then it is the linker that threw them away.

This is not rocket science...
No, but understanding and correctly using the weak and used function and variable attributes is key here.

A real stub function, when using GCC, is therefore usually
    rettype __name(arglist) { /* default implementation */ }
    rettype name(arglist) __attribute__((used, weak, alias ("__name")));
which lets anyone reimplement the name() function, but still have access to the default __name() version also.  Many projects use a macro (taking the return type, name, argument list with surrounding parentheses, and the default implementation body as parameters) if there are a few of these.

peter-h, note that I edited my previous post after you posted your previous post; there might be something useful there for you.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #21 on: June 13, 2022, 09:30:59 pm »
Quote
SRAM occupied by the boot code would not be available to the user code.

Indeed; the 32k boot block is standalone. It cannot call functions outside of itself, and outside code cannot call anything in it (except the RAM-based boot loader, about 3k, which lives within this boot block and gets copied from there to RAM, just below the top of RAM, does its job, and the whole thing reboots. And all that works).

Quote
then it is the compiler that never emitted the code for the function, and __attribute__((used)) should fix it.

The main_real stuff is in the .map file in the right place



so yeah it looks like the linker has removed it because this is what is in there



The (used) attrib doesn't work, unless I am not using it right (see posts above).


Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #22 on: June 13, 2022, 09:35:43 pm »
Are you sure that your .text sections from the KDE_main_stub.o did not get collected by previous more generic statements? Linker scripts are processed linearly. If there is a more generic statement first, it will collect the values. The following statement would be useless.

But again, what you are doing is very bad and will cause users to curse you. There is no need for this. What you are doing is a very well solved problem with known solutions.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #23 on: June 13, 2022, 09:47:24 pm »
See my post above. KDE_main_stub is shown (in the .map file) at 0x8008000, which is right. It's just that there isn't any code at that address, so that function has been stripped out, presumably because nothing is calling it.

You are right; this is a funny way to do it. I think the problem appears because I am trying to build the whole project (boot block and the "overlay") in one go, which absolutely does work, not least because the boot block calls the first function in the overlay (main()), whereas if I create a separate Cube "devkit" for somebody, which just builds the "overlay", located at 0x8008000, they won't have the problem because, one hopes, nothing is going to strip out their main(). But why will their main() not get stripped out? My guess is that in the arm32/gcc setup, a vector is always pointing at main(), so main() can be anywhere within the FLASH.

So what can I do to prevent main() getting stripped out here? I've tried everything I can think of. Maybe I should point some unused vector (table at 0x8008000+0x200) at it :) Not kidding - that does actually work! Asm code is not optimised out. But causes some other issue. Another way which works is to reference main() with this, where the code after the asm(... is never executed



Unfortunately both above methods cause a hard fault handler IRQ0, after this point





where the code looks plausible, SP is 0x2001fd98 which is ok... This is the hard fault data



I wonder if this hex dump of memory at 8008000 gives a clue. Bit 1 is not 1, is it?



The trap is generated by the push r7, lr instruction. r7=0, lr=0x800163d. Is that a write into FLASH? Maybe in GCC C you cannot just jump to a C function. Maybe some setup is needed first. But I struggle to see a significant difference between jumping to main() and calling main() from C, in terms of register values.

It is really stupid for a compiler to be so determined to remove code. I am running the project with -Og, but this module has the -O0 attribute. This is GCC 10. Maybe they were running out of ideas after GCC9?

This stuff used to be so easy.
ORG 0x100
some code
ORG 0x8000
some code
ORG 0xF000
some code
etc
and it all worked.
« Last Edit: June 13, 2022, 10:21:58 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #24 on: June 13, 2022, 10:34:58 pm »
No, your map shows the file, but it does not show that any functions from this file were included in the current section, possibly because they all were already collected in previous sections. Or your matching filters for ".text" and other stuff did not match anything.

This stuff is still easy, just done a bit differently. And you completely refuse to acknowledge that difference.

Let them build overlay with the vector table at the beginning, so they won't have to do the same stupidity as you are doing here. And treat that application as any normal bootloader would. And all they would need to do is specify a new offset for the code without changing anything else in their application.


And you can do the same - just place the new vector table at that address and everything else would used automatically because  it is refereed from the vector table.
« Last Edit: June 13, 2022, 10:41:35 pm by ataradov »
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #25 on: June 14, 2022, 06:42:24 am »
Quote
possibly because they all were already collected in previous sections

This is not happening. The .map file shows KDE_main_stub at 0x8008000, or not, according to whether the entry point main() is referenced somewhere, or not.

Is it actually possible to do a simple asm jump to an address of a GCC function, without setting up some registers etc?
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #26 on: June 14, 2022, 06:51:46 am »
The .map file shows KDE_main_stub at 0x8008000
Where? In the screenshots you showed it shows that KDE_main_stub.o is at that address with no code used from this file. The same file can provide code for multiple locations.

Is it actually possible to do a simple asm jump to an address of a GCC function, without setting up some registers etc?

This does jump to a (void) function
Code: [Select]
  asm("bx %0"::"r" (addr));
addr must have LSB set.

Or, if address is fixed then "bl" instruction would do the same.
Alex
 

Offline Fungus

  • Super Contributor
  • ***
  • Posts: 16642
  • Country: 00
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #27 on: June 14, 2022, 06:54:04 am »
Of course, the "answers" are all over the internet, but none of them compile, or (if they compile) none work.

I have what is basically an overlay at FLASH base+32k ie.. 0x08008000 and need to jump to that address.

Push it on the stack and do a RET.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #28 on: June 14, 2022, 07:04:06 am »
Quote
This does jump to a (void) function

Main() is an "int" not a "void". I can't change that; the compiler requires a function called "main" to be "int" :)

Quote
addr must have LSB set.

This matters. Now it works. Previously I tested with and without, and was misguided by this example above :) The compiler does not "figure it out".




But the bit in yellow (which never runs) is still needed to prevent the target code disappearing.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #29 on: June 14, 2022, 07:08:20 am »
Main() is an "int" not a "void".
I meant the arguments. Return type does not matter, but you have to fill out the arguments if the function takes them.

The compiler does not "figure it out".
Why would it? This is a behaviour specific to the implementation. On device with full ARM/Thumb-2 support either one will work and will switch the mode. On Thump-2 only devices you must remain in the Thumb-2 state, so LSB=1 is mandatory on all calls. Otherwise you will get INSTATE exception.

But again, let me advocate for your customers. What you are doing is just stupid. Don't do this. Place the vector table directly at the 0x08008000 address and jump there as a normal bootloader would. This way customers won't have to see with linker scripts.
« Last Edit: June 14, 2022, 07:10:53 am by ataradov »
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #30 on: June 14, 2022, 07:12:49 am »
What arguments does a
int main(void)
have, and how do I set them up in assembler?

Quote
Place the vector table directly at the 0x08008000 address and jump there as a normal bootloader would.

Yes; that would address the code removal because main() will have something pointing to it, which normally happens in a ST arm32 environment. Thanks.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #31 on: June 14, 2022, 07:14:31 am »
What arguments does a
int main(void)
have, and how do I set them up in assembler?
None. That's why I said it must be a (void) function. You don't need to do anything extra.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #32 on: June 14, 2022, 07:58:41 am »
OK, thanks. This all works now.

I actually did it a bit differently. This is the vector table in the "overlay". It is a copy of the standard table.



The _estack word should be redundant since SP is already set to top of RAM from the boot block, but putting 0 in there bombs it all, and I found it is required because the RTOS directly fetches that value for its internal use :)

The reset_handler is indeed redundant and I can't see it being used because a reset also clears VTOR, so the table in the boot block gets used instead, which is as intended.

If one did this scheme where the vector table, instead of main(), is at the base of the overlay, one would have to enter the overlay by faking a hardware reset (but without changing VTOR - how?) to produce a jump to the 2nd vector and that would say

 .word main

Or one would read out the 2nd vector value with code, and jmp to that, which doesn't actually get you anything.

I eliminated the code disappearance with



so there is a permanent (if unused) reference to main() which is non-removable because it is in an asm file.

The reason what I am doing seems weird is partly because I am not fully familiar with the arm32 environment (who is, at ~10k pages?) and partly because I am juggling multiple objectives which I have not posted here, partly for brevity and partly because I don't want to tell you all what I am developing ;)

The reason why the various "keep" directives (in the C source and in the linkfile) seem to do nothing, remains unsolved. But I am not surprised; most websites that list compiler and linker directives are duff because there are so many versions. One can spend literally days on that.
« Last Edit: June 14, 2022, 08:37:53 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #33 on: June 14, 2022, 04:17:25 pm »
SP is not redundant, If the code is compiled in the outside project, the project may want to place SP in a different place.

Same with the reset handler. The secondary project will need to initialize its own memory. You are thinking about your embedded project. But this will not work with the standalone project at all.

Right now it all works because reset handler of your main project loads the data for the initialized variables from the second part. But as soon as you replace the second part, none of this data would be valid.

Do not deviate from standard stuff. You are just going to miss something like this. You need to have both values.

And it is much better to develop systems like this with the outside project first and then implement embedded projects. You will immediately see all the issues I'm describing.
« Last Edit: June 14, 2022, 04:20:30 pm by ataradov »
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #34 on: June 14, 2022, 05:27:07 pm »
Not quite, but I can see I didn't describe it fully.

The boot block always gets entered after a reset. There is no way for a 32F4 to do otherwise, because VTOR is set to zero.

The boot block is standalone; it doesn't call anything outside and nothing outside of it calls it. There is no variable sharing either. No data is passed between the two (except via data in a serial FLASH).

When control is passed to the "overlay" the SP is set to top of the RAM. C doesn't move the SP. That stack is also used for interrupts. FreeRTOS sets up its own task stacks in a chunk of RAM you give it and it does its own SP switching there.

The "overlay" never runs standalone. The boot block always runs first, and initialises most of the hardware.

This separation was done to enable later replacement of the "overlay".

I've designed other products like this. In one of them, the "overlay" can call functions in the boot block (due to memory limits, the boot block contained bulky functions like float maths) but to prevent obvious address problems across code versions, the boot block has a function address table in a fixed location and calls go via that. On this product there is no such function sharing.

I had some fun and games e.g. there was a data copy loop in the boot block which the compiler detected could be replaced with a memcpy() but memcpy is in a huge code library which wasn't in the boot block. There is probably a way to check for this by doing sed/grep on the symbol table. So that function is compiled with a -O0 attribute.

In a scenario where I know the overlay will never be replaced, I would build the project as a single project, but the above mentioned separation can be maintained even though it is not needed.

One reason for the boot block is to prevent a corrupted (or buggy) overlay from bricking the device. A "standard factory overlay" will always be available in a serial FLASH from where it can be restored.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #35 on: June 14, 2022, 05:36:02 pm »
I understand you perfectly and saying that you are wrong. If you put an arbitrary standalone project binary into the second part, but skip the reset handler, what code would be initializing the global variables for that code? You main boot program can't do that  because it does not know anything about that binary. So, if you jump into the main() directly, all your BSS memory would not be zeroed out and initialized memory would not  be initialized.

SP is less critical, but it is still a good idea to give control over it to the application. It might not want to have it at the end of SRAM. The binary may want to reserve some SRAM at the end.
Alex
 
The following users thanked this post: newbrain, SiliconWizard

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #36 on: June 14, 2022, 06:29:33 pm »
Indeed, any development environment which generates just the "overlay" would have code in main() which sets up the BSS and the initialised statics.

I had the same issue with the boot loader. There, it was done in C:

Code: [Select]
extern char _loader_start;
extern char _loader_end;
extern char _loader_loadaddr;
extern char _loader_bss_start;
extern char _loader_bss_end;

// Copy loader code to RAM. This also sets up its initialised data.
B_memcpy(&_loader_start, &_loader_loadaddr, &_loader_end - &_loader_start);

// Clear loader's BSS and COMMON
B_memset(&_loader_bss_start, 0, &_loader_bss_end - &_loader_bss_start);

extern void loader_entry() __attribute__((long_call));
loader_entry();

// never get here (loader always reboots)
for (;;);
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #37 on: June 14, 2022, 06:38:05 pm »
Indeed, any development environment which generates just the "overlay" would have code in main() which sets up the BSS and the initialised statics.
But why? All the reset handler is doing is this initialization and a call to main, except if you instruct people to place main() a a reset vector, you will also have to explain to them rules for BSS and data initialization and have them copy the code from the reset handler. And all you had to do to avoid all this is literally do nothing. Just keep the reset handler in the vector table and everything will work with standard environments.

All you have here is a standard bootloader, just behave like normal bootloaders behave and people will have no issues using your stuff. But you are inventing something that would be confusing to anyone familiar with how any of this works.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #38 on: June 14, 2022, 07:38:03 pm »
A development environment which builds just the overlay would be the same as my current one, minus the boot block.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11236
  • Country: us
    • Personal site
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #39 on: June 14, 2022, 07:53:04 pm »
Why are you mandating the development environment? Why not let user pick what they want to do?

Anyway, do whatever you want, I'm not going to be the user, and that makes me happy.
Alex
 
The following users thanked this post: langwadt, newbrain

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3694
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 32F417 how to call or jump to a specific address?
« Reply #40 on: June 14, 2022, 08:26:41 pm »
This is a product which my little company will have to support (possibly for a long time; it's been running since 1991) and not everybody is as clever as you :) I certainly am not. But I much prefer working with people who are much more clever than I am, so if I am looking for somebody one day I will give you a shout ;)

Thanks everyone for all your help. It's running fine now.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf