GCC PowerPC avoids .rodata section for floats

I am writing C code and compiling it for a PowerPC architecture. At the same time, the C code contains floating point variable variables that I want to put in the .text section instead of .rodata , so the function code is autonomous.

The problem is that in PowerPC , the only way to move a floating point value to a floating point register is to load it from memory . This is a limitation of the set of instructions.

To convince GCC to help me, I tried to declare a float as a static const . No difference. Using pointers, same results. Using __attribute__((section(".text"))) for a function, the same results for each floating point variable individually:

 error: myFloatConstant causes a section type conflict with myFunction 

I also tried disabling optimization using #pragma GCC push_options #pragma GCC optimize("O0") and #pragma GCC pop_options . Plus, I pretend that I have an unsigned int :

 unsigned int *myFloatConstant = (unsigned int *) (0x11000018); *myFloatConstant = 0x4C000000; 

Using float:

 float theActualFloat = *(float *) myFloatConstant; 

I would still like to save -O3 , but it uses .rodata again, so the potential response would include an optimization flag which creates floats in .rodata starting with -O1 does this happen?

The best scenario is that I can use the “usually” float in the code plus the maximum optimization, and they will never fit in .rodata at all.

I believe that GCC will probably place the float constant between the code by mixing the data and the code, loading from this place into the floating point register, and continuing. It can be written manually, I believe, but how to make GCC do it? Forcing an attribute on a variable causes an error from above, but technically this should be feasible.

+7
c assembly gcc floating-point powerpc
source share
2 answers

Using GCC 7.1.0 powerpc-eabi (cross-compiler for Linux), the following code worked for me:

 float test(void) { int x; volatile float y; float theActualFloat; *(float *)&x = 1.2345f; *(int *)&y = x; theActualFloat = y; return theActualFloat; } 

Final build code:

 test: stwu 1,-24(1) lis 9,0x3f9e ori 9,9,0x419 stw 9,8(1) lfs 1,8(1) addi 1,1,24 blr 

Explaination:

In the line *(float *)&x = value you write an integer that will be optimized by the compiler. The compiler will perform an integer operation that does not receive floating point values ​​in .rodata .

The string *(int *)&y = x in any case purely integer.

theActualFloat = y cannot be optimized due to volatile , so the compiler must write an integer to the variable on the stack, and it must read the result from the variable.

+3
source share

I found another solution that avoids creating a stack frame and .rodata , but requires an absolute memory address to store the float in:

 static inline volatile float *getFloatPointer(int address, float value) { float *pointer = (float *) address; *pointer = value; return pointer; } 

It is used as follows:

 volatile float *myFloat = getFloatPointer(0x12345678, 30.f); printf("%f", *myFloat); 

It is important not to create a local float variable, only volatile pointers, so it will not use .rodata again.

0
source share

All Articles