Does clang support to generate GOT-based position indenpendent code with pic-register?

I’m trying to use arm-llvm at GitHub - ARM-software/LLVM-embedded-toolchain-for-Arm: A project dedicated to build LLVM toolchain for 32-bit Arm embedded targets..
I want to generate position independent code with pic-register. I know how to do this with GCC by using options -fPIC -msingle-pic-base -mpic-register=r9.

I post a issue in the arm repository:

The ARM guy told me clang have no GCC’s PIC configuration options, and told me to ask here.
Acutally I also asked another ARM guy, but gives me no answer.

So, what he mean is clang does not have equivalent options as GCC pic options or clang does not support this? I mean support to generate pic code with pic-register, which is normally R9 in ARM chips.

I think you’re looking for -frwpi?

1 Like

Thanks, i found it’s supported in serveral years ago, ⚙ D23195 [ARM] Add support for embedded position-independent code.
Should be -fropi and -frwpi.

I have tried -fropi and -frwpi. It is used for embedded position indenpendent, and it’s not equivalent to GCC options -fPIC -msingle-pic-base -mpic-register=r9. Because for GCC case with these options, GOT-based position indenpendence code is generated(with section .plt, .got and .got.plt), and static base register r9 is the address of the GOT.

So is there any option in clang to generate GOT-based position indenpendence code with r9 as GOT address? I now, understand why the ARM guy don’t know this.

I have edited the title to avoid ambiguous information.

I found this:

there is an option to armclang, -fbare-metal-pie, but not available in clang. So this is not a free feature.

I was very confused why you’d want something like this, but then I realized the key option is actually -mno-pic-data-is-text-relative. Which allows the loader to shift around both the GOT and global variables relative to the code. So, similar to -frwpi, but worse, because it needs an extra indirection to compute the addresses of global variables.

No, clang currently doesn’t support that ABI. But I expect it would be straightforward to port your code to use -frwpi instead.

I’m implementing a fake linux in cortex-m chips, almost done. Now, I’m adding a dynamic load feature. All the code is in flash, so GOT is needed to do all the reallocating.

I’m fimilar with GCC, so I know the options in GCC to generate the code I want, although there is a BUG in GCC while accessing GOT in veneer functions, which will use PC + offset instead of static base R9, but this can be patched. This bug exists in arm-none-eabi-gcc at least seversal years ago.

So, my loader will allocate bss and data section, and generate a GOT table according to rel(for variable) and jmprel(for functions) sections, and pass to R9. I will implement a POC with GCC, if all done. I will try to use clang, because even if the same bug exists in llvm, the ARM guys will fix it, but they will not fix the same bug in arm-none-eabi-gcc.

For GCC, it’s working on Cortex-M4 chips.

Command lines are:
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -fPIC -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -Wall -g -O2 -c main.c -o main.o
arm-none-eabi-gcc -shared -fPIC -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -nostdlib -o main.elf main.o
arm-none-eabi-strip main.elf

A GOT-based position independent elf target will be generated. And while loading the elf, just allocate .bss, .data, .noinit and .got sections. All relocations will be applied to GOT sections. So .text, .plt and .rodata sections remain in flash(XIP).

for ropi/rwpi(embedded position independent), I have no idea how external symbols are relocated. I have read the source code of a ropi/rwpi loader, but can not find the relocation of extern symbols. Maybe only GOT-based position independent can support this. As in the image, there is a log about reloate printf, this is a external symbol.

clang support is done, implemented by a virtual_plt. Because clang will not generate plt for external functions. So simply construct a virtual plt. _start entry should accept 3 parameters, the last one is pointer to virtual plt provided by loader.

In the main.c file, main and printf MACROs should be put in c headers instead of in user main.c file.

rust + llvm is done, just the same.