You copied the Doc URL to your clipboard.

Bare-metal Position Independent Executables

A bare-metal Position Independent Executable (PIE) is an executable that does not need to be executed at a specific address. It can be executed at any suitably aligned address.


  • Bare-metal PIE support is deprecated.
  • There is support for -fropi and -frwpi in armclang. You can use these options to create bare-metal position independent executables.

Position independent code uses PC-relative addressing modes where possible and otherwise accesses global data via the Global Offset Table (GOT). The address entries in the GOT and initialized pointers in the data area are updated with the executable load address when the executable runs for the first time.

All objects and libraries that are linked into the image must be compiled to be position independent.

Compiling and linking a bare-metal PIE

Consider the following simple example code:

#include <stdio.h>

int main(void) 
  printf("Hello World!\n");
  return 0;

To compile and automatically link this code for bare-metal PIE, use the -fbare-metal-pie option with armclang:

armclang --target=arm-arm-none-eabi -march=armv8-a -fbare-metal-pie hello.c -o hello

Alternatively, you can compile with armclang -fbare-metal-pie and link with armlink --bare_metal_pie as separate steps:

armclang --target=arm-arm-none-eabi -march=armv8-a -fbare-metal-pie -c hello.c
armlink --bare_metal_pie hello.o -o hello 

The resulting executable hello is a bare-metal Position Independent Executable.


Legacy code that is compiled with armcc to be included in a bare-metal PIE must be compiled with either the option --apcs=/fpic or, if it contains no references to global data, the option --apcs=/ropi.

If you are using link time optimization, use the armlink --lto_relocation_model=pic option to tell the link time optimizer to produce position independent code:

armclang --target=arm-arm-none-eabi -march=armv8-a -flto -fbare-metal-pie -c hello.c -o hello.bc
armlink --lto --lto_relocation_model=pic --bare_metal_pie hello.bc -o hello


A bare-metal PIE executable must conform to the following:

  • AArch32 state only.
  • The .got section must be placed in a writable region.
  • All references to symbols must be resolved at link time.
  • The image must be linked Position Independent with a base address of 0x0.
  • The code and data must be linked at a fixed offset from each other.
  • The stack must be set up before the runtime relocation routine __arm_relocate_pie_ is called. This means that the stack initialization code must only use PC-relative addressing if it is part of the image code.
  • It is the responsibility of the target platform that loads the PIE to ensure that the ZI region is zero-initialized.
  • When writing assembly code for position independence, some instructions (LDR, for example) let you specify a PC-relative address in the form of a label. For example:

    LDR r0,=__main

    This causes the link step to fail when building with --bare-metal-pie, because the symbol is in a read-only section. armlink returns an error message, for example:

    Error: L6084E: Dynamic relocation from #REL:0 in unwritable section foo-7cb47a.o(.text.main) of type R_ARM_RELATIVE to symbol main cannot be applied.

    The workaround is to specify symbols indirectly in a writable section, for example:

        LDR r0, __main_addr
    __main_addr DCD __main

Using a scatter file

An example scatter file is:

LR 0x0 PI
    er_ro +0 { *(+RO) }

    got +0 { *(.got) }
    er_rw +0 { *(+RW) }
    er_zi +0 { *(+ZI) }

    ; Add any stack and heap section required by the user supplied
    ; stack/heap initialization routine here

The linker generates the DYNAMIC_RELOCATION_TABLE section. This section must be placed in an execution region called DYNAMIC_RELOCATION_TABLE. This allows the runtime relocation routine __arm_relocate_pie_ that is provided in the C library to locate the start and end of the table using the symbols Image$$DYNAMIC_RELOCATION_TABLE$$Base and Image$$DYNAMIC_RELOCATION_TABLE$$Limit.

When using a scatter file and the default entry code that the C library supplies, the linker requires that you provide your own routine for initializing the stack and heap. This user supplied stack and heap routine is run before the routine __arm_relocate_pie_, so it is necessary to ensure that this routine only uses PC relative addressing.