Trying to compile with -static-pie for a bare-metal target: no dynamic linker and therefore the relocations have to be resolved by the ELF loader when it establishes a load address or the executable itself at init by iterating over the relocatable sections. The problem is that after linking, the output ELF doesn't contain relocations. Also attached the output when compiling for aarch64. $ cat simple.c typedef void (*fptr)(void); void func1(void) {} void func2(void) {} const fptr table[] = { func1, func2, }; int _start(int i) { table[i](); } $ cat linker.ld ENTRY(_start) SECTIONS { . = 0x00001000; } --------------------------------------------------------------------------------------------------------------- RISC-V: - GCC: riscv64-unknown-elf-gcc (GCC) 9.2.0 - binutils: GNU ld (GNU Binutils) 2.32 $ riscv64-unknown-elf-gcc -fPIE -c simple.c -o simple.riscv.o $ riscv64-unknown-elf-readelf -r simple.riscv.o Relocation section '.rela.text' at offset 0x278 contains 4 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000050 000b00000017 R_RISCV_PCREL_HI2 0000000000000000 table + 0 000000000050 000000000033 R_RISCV_RELAX 0 000000000054 000600000018 R_RISCV_PCREL_LO1 0000000000000050 .L0 + 0 000000000054 000000000033 R_RISCV_RELAX 0 Relocation section '.rela.data.rel.ro.local' at offset 0x2d8 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000000 000900000002 R_RISCV_64 0000000000000000 func1 + 0 000000000008 000a00000002 R_RISCV_64 000000000000001c func2 + 0 $ riscv64-unknown-elf-gcc -nostdlib -nostartfiles -T linker.ld -static-pie simple.riscv.o -o simple.riscv.elf $ riscv64-unknown-elf-readelf -r simple.riscv.elf There are no relocations in this file. simple.riscv.elf is "Type: EXEC (Executable file)" --------------------------------------------------------------------------------------------------------------- aarch64: - GCC: aarch64-linux-gcc.br_real (Buildroot 2018.11-rc2-00003-ga0787e9) 8.2.0 - binutils: GNU ld (GNU Binutils) 2.31.1 $ aarch64-linux-gcc -fPIE -c simple.c -o simple.aarch64.o $ aarch64-linux-readelf -r simple.aarch64.o Relocation section '.rela.text' at offset 0x2d8 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000000001c 000e00000113 R_AARCH64_ADR_PRE 0000000000000000 table + 0 000000000020 000e00000115 R_AARCH64_ADD_ABS 0000000000000000 table + 0 Relocation section '.rela.data.rel.ro.local' at offset 0x308 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000000 000c00000101 R_AARCH64_ABS64 0000000000000000 func1 + 0 000000000008 000d00000101 R_AARCH64_ABS64 0000000000000008 func2 + 0 Relocation section '.rela.eh_frame' at offset 0x338 contains 3 entries: Offset Info Type Sym. Value Sym. Name + Addend 00000000001c 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 0 000000000030 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 8 000000000044 000200000105 R_AARCH64_PREL32 0000000000000000 .text + 10 $ aarch64-linux-gcc -nostdlib -nostartfiles -T linker.ld -static-pie simple.aarch64.o -o simple.aarch64.elf $ aarch64-linux-readelf -r simple.aarch64.elf Relocation section '.rela.dyn' at offset 0x1148 contains 2 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000001178 000000000403 R_AARCH64_RELATIV 1000 000000001180 000000000403 R_AARCH64_RELATIV 1008 simple.aarch64.elf is "Type: DYN (Shared object file)"
I see two problems here. The first problem is that the RISC-V GCC port isn't handling the --static-pie option. For targets that support it, --static-pie should be translated to the linker options "--static --pie --no-dynamic-linker -z text". This doesn't happen for RISC-V as the gcc support is missing. The second problem is that if I manually specify the missing linker options then I get a linker error "-pie is not supported". We do not have support for shared libraries in our embedded toolchain because no one has done a RISC-V shared library port of newlib yet. I get binutils testsuite errors if I enable shared library support, which makes it harder to spot testsuite regressions. Also, I used to get bug reports from users asking why the shared library support was broken because they couldn't get it working. It isn't broken, it is because the newlib support is missing. If I use a linux toolchain, and manually specify the missing linker options, then it works correctly. But the linux toolchain isn't designed for bare metal targets so that probably isn't usable as a workaround. The GCC bug should be fixed and looks easy enough. You could hack around the binutils problem by reverting the patch that disabled shared library support in the embedded elf toolchain. Or maybe I should consider re-enabling the support and find some other way to handle the newlib and testsuite problems. You don't need shared libraries to make static pie work. And the boot loader folks would also like to be able to use static pie or something similar.
Hi Jim, Are there any news/updates regarding this? Seems like there were 2 problems: 1) GCC doesn't propagate "--static-pie" as "--static --pie --no-dynamic-linker -z text" to the linker 2) Newlib doesn't support building as a shared library (required by --pie), which shouldn't be needed for either bare-metal or static-pie Have those been fixed? If not, do you have patches, that maybe are not ready yet for upstreaming, but that fix those issues? Thanks!
I don't know of anyone working on any of these problems. So no progress.
gcc 14 will support -static-pie for linux configurations.