Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guessing the VTOR wrong #314

Open
pfef-to opened this issue Apr 1, 2022 · 5 comments
Open

Guessing the VTOR wrong #314

pfef-to opened this issue Apr 1, 2022 · 5 comments

Comments

@pfef-to
Copy link

pfef-to commented Apr 1, 2022

Looking at the initialization code for Cortex-M, it seems that the VTOR is guessed by finding the ELF section with the lowest address. The function used is called GetSectionPhysicalAddress, yet it actually looks up the SectionLoadAddress. In my case, this returns the wrong VTOR address, as my binary contains an allocatable empty section with no address (LoadAddress is zero).

I'd suggest using the lowest physical segment address for loaded segments instead, as these are sure to be loaded at the specified address.

Snippet from the section table of my example:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .isr_vector       PROGBITS        08000000 010000 0001f8 00   A  0   0  4 <-- actual VTOR
  [ 2] .vectors          PROGBITS        00000000 037898 000000 00   W  0   0  1
  [ 3] .fastcode         PROGBITS        00000000 037898 000000 00   W  0   0  4
  [ 4] .heap4            NOBITS          00000000 020000 004000 00  WA  0   0  1  <-- allocatable at 0x0
  [ 5] .stack            NOBITS          20000000 040000 000be0 00  WA  0   0  1
  [ 6] .fastdata         PROGBITS        20000be0 010be0 00000c 00  WA  0   0  4
  [ 7] .heap0            NOBITS          20000bec 010bec 00f414 00  WA  0   0  1
  [ 8] .backup           PROGBITS        40024000 037898 000000 00   W  0   0  4
  [ 9] .heap5            NOBITS          40024000 014000 001000 00  WA  0   0  1
  [10] .text             PROGBITS        08000210 020210 006e40 00  AX  0   0 16

Snippet from the segment table of my example:

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  EXIDX          0x027798 0x08007798 0x08007798 0x00008 0x00008 R   0x4
  LOAD           0x010000 0x08000000 0x08000000 0x001f8 0x001f8 R   0x10000 <-- correct VTOR address
  LOAD           0x000000 0x00000000 0x080001f8 0x00000 0x04000 RW  0x10000 <-- .heap4 loaded after VTOR
  LOAD           0x010be0 0x20000be0 0x080001f8 0x0000c 0x0f420 RW  0x10000
  LOAD           0x004000 0x40024000 0x08000204 0x00000 0x01000 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .ARM.exidx 
   01     .isr_vector <-- VTOR at first loaded segment
   02     .heap4 
   03     .fastdata .heap0 
@PiotrZierhoffer
Copy link
Member

Thanks @pfef-to, that's an interesting find. We'll look into this and pass this through our tests.

For the record, you can always override the guessing with cpu VectorTableOffset 0xYourValue, but we'd definitely want to get the guessing right.

I wonder what's the source of your layout - is this some very specific linker script? Is it something we could reproduce?

@pfef-to
Copy link
Author

pfef-to commented Apr 1, 2022

The project is built with XPCC https://github.com/roboterclubaachen/xpcc (which - admittedly - is deprecated). The linkerscript is compiled from the macros in https://github.com/roboterclubaachen/xpcc/tree/develop/src/xpcc/architecture/platform/driver/core/cortex

@tobermory
Copy link

tobermory commented Apr 27, 2022

My understanding of the VTOR register (as accessed via SCB->VTOR) in Cortex M is that it starts life as 0 upon chip reset. Any change to that value is then the responsibility of software. For example, a bootloader loaded at 0 would do this to load an application built for 0x1000:

SCB->VTOR = 0x1000;

Alternatively, the application could set it itself. In fact, the CMSIS standard startup/system code does this for you:

Device/ARM/ARMCM3/Source/system_ARMCM3.c:

SCB->VTOR = (uint32_t) &__VECTOR_TABLE;

MCU vendors (I use SiliconLabs parts) do similar in their supplied startup files.

Given this, I am confused why/how there is any 'guessing' of the VTOR.

@pfef-to
Copy link
Author

pfef-to commented Apr 28, 2022

Yeah sorry that wording might've been wrong. As I understand it, it is guessing the vectors table address - so in other words the value to assign to the VTOR. It is basically doing what the bootloader would do and but it doesn't know about the 0x1000 from your example so it has to guess (@PiotrZierhoffer correct me if I'm wrong).

@PiotrZierhoffer
Copy link
Member

@tobermory that's exactly the case: we don't always run all the bootloaders, because we don't have to. Very often we just run our ELFs to memory and execute from there, but this means that we need to have some idea about the processor configuration.

It's customary that Cortex-M binaries begin with VTOR, so that's why we can guess it. You don't have to - you can set it manually, but it turns out that for most of the software we tried guessing is good enough.

@pfef-to it took us some time to schedule this, but we'll be testing your changes very soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants