[PATCH] D136203: [ARM] Support -mexecute-only with -mlong-calls.

Zhiyao Ma via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 18 16:50:07 PDT 2022


ZhiyaoMa98 added a comment.

> Can you describe a little more what you're trying to do here?

Sure. My eventual goal is to enable fine-granular live-update on ARM based microcontrollers, which requires the system to do some relocation at runtime. Below I will describe the challenge with a simple C example.

Consider the following C snippet:

  extern void global_func(void); // A global function whose symbol is exported by the system at runtime.
  static void local_func(void) { ... }
  
  static void main_entry(void) {
      local_func();
      global_func();
  }

I want to load and run the compiled object file at runtime, which requires two steps.

1. Burn the object file into Flash storage.
2. Perform a runtime symbol resolution and relocation so that `global_func` is set to the runtime address.

The reason why I must store code in Flash storage is that the microcontroller I am using, as well as many other ARM based microcontrollers, has Flash storage 5x greater than RAM, and code typically directly runs from Flash.

`local_func` requires the compiler to use position independent code, which has already been handled by `-fropi`. `global_func` however, is the case I am trying to solve here.

Existing compiler options always store the address of `global_func` in Flash.

The default case:

  main_entry:
      bl  local_func
      b.w global_func // Relative address is hardcoded in the instruction, in Flash.

If compile with `-mlong-calls`:

  main_entry:
      bl  local_func
      ldr r0, [pc, #4] // Load address from constant pool, still in Flash.
      bx  r0
  .Lconst_pool:
      .word global_func

In the hypothetical case if the compiler chose to use `movw` `movt` pair:

  main_entry:
      bl   local_func
      movw r0, :lower16:global_func // Absolute address is hardcoded in the instruction, still in Flash.
      movt r0, :upper16:global_func
      bx.  r0

I was expecting to use the "side effect" of `-mexecute-only` that promotes constant pools to global variables to achieve my goal of having the function address to live in RAM.

  main_entry:
      bl   local_func
      movw r0, :lower16:.const_pool(sbrel) // Absolute address is held in RAM now.
      movt r0, :upper16:.const_pool(sbrel) // Also using RWPI so that the jump table can be placed anywhere in RAM pointed by r9.
      ldr  r0, [r9, r0]
      bx   r0

As you have already pointed out, in the normal case when we do not need to put the address in RAM, the extra indirection is unnecessary and slows down the code.

But if I have a use case like above where I need to store the address in RAM, could you enlighten me about the best approach to achieve my goal?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136203/new/

https://reviews.llvm.org/D136203



More information about the llvm-commits mailing list