3.5 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 but can be executed at any suitably aligned address.

Note:

  • 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 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\n”);
  return 0;
}

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

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

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

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

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

Note:

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 it may be compiled with 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 -flto -fbare-metal-pie --target=arm-arm-none-eabi -march=armv8-a -c hello.c -o hello.bc
armlink --lto --lto_relocation_model=pic --bare_metal_pie hello.bc -o hello

Restrictions

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, be aware that 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. The workaround is to specify symbols indirectly in a writable section, for example:

        LDR r0, __main_addr
    ...
        AREA WRITE_TEST, DATA, READWRITE
    __main_addr DCD __main
        END

Using a scatter file

An example scatter file is:

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

    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 supplied by the C library the linker requires that the user provides their own routine for initializing the stack and heap. This user supplied stack and heap routine is run prior to the routine __arm_relocate_pie_ so it is necessary to ensure that this routine only uses PC relative addressing.

Non-ConfidentialPDF file icon PDF versionDUI0773J
Copyright © 2014–2017, 2019 Arm Limited or its affiliates. All rights reserved.