Keil Logo

ARMLINK: prevent constant literal pool sharing over region borders


Information in this knowledgebase article applies to:

  • MDK
  • Arm Compiler 6

QUESTION

In our application we use the same constant value in different C modules of the project. To demonstrate this, two simple source files can be used:

/* main.c */
int optional( void ) ;

int main( void )
{
  optional( ) ;  /* in real world, called later */
  return( 0x12345678 ) ;
}
/* optional.c */
int optional( void )
{
  return( 0x12345678 ) ;
}

The compiler creates a literal pool with this constant in each module.
One of the C modules gets linked into a separate execution region. The scatter file can look like this:

LR_IROM1 0x00000000 0x00000800  {    ; load region size_region
  ER_IROM1 0x00000000 0x00000800  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00020000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

LR_IROM2 0x00000800 0x00000800  {
  ER_IROM2 0x00000800 0x00000800  {  ; load address = execution address
    optional.o (+RO)
  }
}

When looking at the build result we noticed, that the identical constant in literal pools got merged and shared between the load regions, while the actual value is stored in the region into with the module optional.o was linked.

     5:   optional( ) ;
0x00000452 F000F9D5  BL.W     optional (0x00000800)
0x00000456 48EB      LDR      r0,[pc,#940]  ; @0x00000804
     6:   return( 0x12345678 ) ;

0x00000800 4800      LDR      r0,[pc,#0]  ; @0x00000804
     3:   return( 0x12345678 ) ;
0x00000802 4770      BX       lr
0x00000804 5678      DCW      0x5678
0x00000806 1234      DCW      0x1234

This is an issue, when the region with optional.o is optionally downloaded like a patch or the regions are protected by a hardware mechanism and haven't the same access rights during runtime.
Linking with --no_merge_litpools is no option, as fully disabling the constant literal pool sharing results in a too large code size for the real application. So, how can constant literal pool sharing over certain region borders be prevented?

ANSWER

Constant literal pool sharing between one and the other regions can be prevented by using the OVERLAY region attribute e. g. like this:

LR_IROM2 0x00000800 OVERLAY 0x00000800  {
  ER_IROM2 0x00000800 0x00000800  {  ; load address = execution address
    optional.o (+RO)
  }
}

This tells the linker, that this region is might not always be available. Because of this, it disables literal pool sharing with this region. The generated code changes accordingly:

     5:   optional( ) ;
0x00000452 F000F9D5  BL.W     optional (0x00000800)
0x00000456 4801      LDR      r0,[pc,#4]  ; @0x0000045C
     6:   return( 0x12345678 ) ;
0x00000458 BD80      POP      {r7,pc}
0x0000045A BF00      NOP
0x0000045C 5678      DCW      0x5678
0x0000045E 1234      DCW      0x1234

0x00000800 4800      LDR      r0,[pc,#0]  ; @0x00000804
     3:   return( 0x12345678 ) ;
0x00000802 4770      BX       lr
0x00000804 5678      DCW      0x5678
0x00000806 1234      DCW      0x1234

As the OVERLAY attribute, which also disables range and overlap checking, has originally a different purpose, you have to manually make sure that regions do not overlap, if this is not intended.

STATUS

For a future linker version the PROTECTED load region attribute will be extended to also cover constant literal pool sharing. Currently it only prevents string literal pool merging.

MORE INFORMATION

Last Reviewed: Thursday, January 30, 2020


Did this article provide the answer you needed?
 
Yes
No
Not Sure
 
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.