Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC PowerPC avoiding .rodata section for floats

I'm writing C code and compile it for the PowerPC architecture. That said C code contains floating point variable constants which I want to be placed in the .text section instead of .rodata so the function code is self-contained.

The problem with this is that in PowerPC, the only way to move a floating point value into a floating point register is by loading it from memory. It is an instruction set restriction.

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

error: myFloatConstant causes a section type conflict with myFunction

I also tried disabling optimizations via #pragma GCC push_options #pragma GCC optimize("O0") and #pragma GCC pop_options. Plus pretending I have an unsigned int worked:

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

Using the float:

float theActualFloat = *(float *) myFloatConstant;

I still would like to keep -O3 but it again uses .rodata so a potential answer would include which optimization flag causes the floats to be placed in .rodata since starting from -O1 this is happening?

Best case scenario would be that I can use floats "normally" in the code plus maximum optimizations and they never get placed in .rodata at all.

What I imagine GCC to possibly do is placing the float constant in-between the code by mixing data and code, loading from that place into a floating point register and continue. This is possible to write manually I believe but how to make GCC do that? Forcing the attribute per variable causes the error from above but technically this should be feasible.

like image 999
BullyWiiPlaza Avatar asked Aug 19 '17 10:08

BullyWiiPlaza


1 Answers

Using GCC 7.1.0 powerpc-eabi (cross compiler under 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;
}

Resulting assembly 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 to an integer which will be optimized by the compiler. The compiler will perform an integer operation which does not access floating point values in .rodata.

The line *(int *)&y = x is a pure integer operation anyway.

The line theActualFloat = y cannot be optimized due to the volatile so the compiler has to write the integer to the variable on the stack and it has to read the result from the variable.

like image 82
Martin Rosenau Avatar answered Oct 21 '22 06:10

Martin Rosenau