Clang and FDPIC on ARM?

I’m working on an OS for embedded ARM without an MMU, but with dynamic loading. I’d like to use an ARM FDPIC-style ABI, where all global data for an ELF loadable module is GOT-relative and r9 is used as the GOT pointer, but there’s no -mfdpic front-end option. How do I achieve this with clang?

Unfortunately there’s no way of doing that in clang. It doesn’t have an implementation of fdpic so someone would need to implement it. It also doesn’t have the more limited, but still GOT based -mno-pic-data-is-text-relative ARM Options (Using the GNU Compiler Collection (GCC))

The closest option that I’m aware of is -frwpi and its read-only equivalent -fropi . That uses r9 for the base of RW data but there is no GOT and no PLT so Unix like shared libraries can’t be implemented. It is suitable for making a single program or loadable module position independent, but it is not suitable for shared libraries.

RWPI is relocation free so it has some limitations. It can’t support statically initialised pointers, these have to be initialised at run-time.

It is possible to make -fpic and -fpie work on a Cortex-M but that isn’t ideal as that really needs a MMU to get the best out of it.

Thanks for the detailed information. It looks like some pieces of ARM FDPIC are implemented in LLVM, specifically in MC and the ELF writer, but they’re not wired up at a higher level and I’m not sufficiently familiar with LLVM internals to know how big a job that would be. My assumption is that clang code generation would need to be adjusted, beyond just propagating FDPIC as an OS ABI from decoding its triple and expecting all the proper relocations to be produced. (Though I do wonder how PowerPC code generation does the equivalent, since the standard ABI is very similar to FDPIC with r2 even being traditionally aliased as rTOC.)

Unfortunately I guess I’ll have to switch to a GNU toolchain for this project, since ELF shared libraries with text sharing (and execute-in-place from flash) are a requirement, and file a feature request against LLVM for FDPIC support. I gather RISC-V is also working on an FDPIC ABI so I’m hopeful it’s something that’ll eventually happen—and like I said, it’s similar to already-supported ABIs for PowerPC, so many of the pieces should already be in place. It’s just not something I can personally take on adding right now.

Edit: I’ve filed the feature request as clang: add support for ARM FDPIC ABI.

I was enthusiastic about FDPIC and wrote a detailed post about it in 2024: MMU-less systems and FDPIC | MaskRay. However, I couldn’t resolve how to model r9 as a call-clobbered register at function entry. I’ve now lost some draft code that simply spilled and restored r9.

I discovered that GCC’s SuperH port leverages a pseudo register and the Integrated Register Allocator pass, leading to nice generated code, while GCC’s ARM port produces less optimal code.

1 Like

It might be worth seeing how targeting ppc-ibm-aix handles r2, since that should be the original PowerPC ABI which used r2 as the pointer to the current loadable module’s Table of Contents for very much the same design goals as FDPIC. I don’t recall whether it was caller- or callee-save, but overall the purpose was the same, and rTOC was an alias to r2 in at least Apple assemblers and the platform used (function pointer, table of contents) routine descriptor pairs too.

PowerPC64 r2 is call-preserved and cannot be used as reference:)

The last paragraph of Linker notes on Power ISA | MaskRay specifies:

If we drop the advantage that a function symbol value points to the function descriptor and fix a few design mistakes:

* Make r2 call-clobbered.
* Remove the unused environment pointer.
* Introduce a relocation to identify a function descriptor and remove compiler-generated `.opd`.

We will essentially get a [FDPIC ABI](https://maskray.me/blog/2024-02-20-mmu-less-systems-and-fdpic)!
1 Like

Do you have any idea how much ARM cares about FDPIC and MMU-less Linux, or how much the RISC-V vendors care? I wonder if they’d invest in getting it implemented in LLVM/clang/lld.

As a member of the Arm compiler team that works on LLVM. This is the first direct request I’ve seen for fdpic support in LLVM. So far it seems like there hasn’t been a lot of observable demand, either upstream or via feature requests from silicon vendors. One possible explanation that I’ve heard is that low-end A-profile CPUs running embedded Linux are a viable alternative for many.

We’ve been aware of fdpic as a potential solution for users needing base-relative position independence on M-profile, but need something more sophisticated than -fropi/-frwpi. Unfortunately without sufficient demand, we’ve not been able to prioritise doing the work. We don’t have fdpic support planned in.