Author Topic: GCC ARM32 32F417 how to call or jump to a specific address?  (Read 2390 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 »
 

Online 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
 

Online 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
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf