GCC PowerPC 避免使用浮点数的 .rodata 部分
GCC PowerPC avoiding .rodata section for floats
我正在编写 C
代码并为 PowerPC
架构编译它。也就是说 C
代码包含浮点变量常量,我想将其放在 .text
部分而不是 .rodata
中,因此函数代码是独立的。
问题在于 PowerPC
、the only way to move a floating point value into a floating point register is by loading it from memory。这是一个指令集限制。
为了说服 GCC
帮助我,我尝试将浮点数声明为 static const
。没有不同。使用指针,结果相同。对函数使用 __attribute__((section(".text")))
,结果相同,每个浮点变量单独使用:
error: myFloatConstant causes a section type conflict with myFunction
我还尝试通过 #pragma GCC push_options
禁用优化
#pragma GCC optimize("O0")
和 #pragma GCC pop_options
。再加上假装我有一个 unsigned int
有效:
unsigned int *myFloatConstant = (unsigned int *) (0x11000018);
*myFloatConstant = 0x4C000000;
使用浮动:
float theActualFloat = *(float *) myFloatConstant;
我仍然想保留 -O3
,但它再次使用 .rodata
,因此可能的答案将包括 which optimization flag causes the floats to be placed in .rodata
,因为从 -O1
开始,这正在发生吗?
最好的情况是我可以在代码中使用浮点数 "normally" 加上最大优化,它们根本不会放在 .rodata
中。
我想 GCC
可能做的是通过混合数据和代码将浮点常量放在代码之间,从那个地方加载到浮点寄存器并继续。我相信这可以手动编写,但是如何让 GCC
做到这一点?强制每个变量的属性会导致上面的错误,但从技术上讲这应该是可行的。
使用 GCC 7.1.0 powerpc-eabi(Linux 下的交叉编译器)以下代码对我有效:
float test(void)
{
int x;
volatile float y;
float theActualFloat;
*(float *)&x = 1.2345f;
*(int *)&y = x;
theActualFloat = y;
return theActualFloat;
}
生成的汇编代码:
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
解释:
在 *(float *)&x = value
行中,您写入一个将由编译器优化的整数。编译器将执行不访问 .rodata
.
中的浮点值的整数运算
*(int *)&y = x
行无论如何都是纯整数运算。
由于 volatile
,theActualFloat = y
行无法优化,因此编译器必须将整数写入堆栈上的变量,并且必须从变量中读取结果。
我找到了另一个解决方案,它避免了 stack frame
创建和 .rodata
使用,但需要一个绝对内存地址来存储浮点数:
static inline volatile float *getFloatPointer(int address, float value) {
float *pointer = (float *) address;
*pointer = value;
return pointer;
}
它是这样使用的:
volatile float *myFloat = getFloatPointer(0x12345678, 30.f);
printf("%f", *myFloat);
重要的是不要创建局部 float
变量,只创建 volatile
指针,这样它就不会再次使用 .rodata
。
我正在编写 C
代码并为 PowerPC
架构编译它。也就是说 C
代码包含浮点变量常量,我想将其放在 .text
部分而不是 .rodata
中,因此函数代码是独立的。
问题在于 PowerPC
、the only way to move a floating point value into a floating point register is by loading it from memory。这是一个指令集限制。
为了说服 GCC
帮助我,我尝试将浮点数声明为 static const
。没有不同。使用指针,结果相同。对函数使用 __attribute__((section(".text")))
,结果相同,每个浮点变量单独使用:
error: myFloatConstant causes a section type conflict with myFunction
我还尝试通过 #pragma GCC push_options
禁用优化
#pragma GCC optimize("O0")
和 #pragma GCC pop_options
。再加上假装我有一个 unsigned int
有效:
unsigned int *myFloatConstant = (unsigned int *) (0x11000018);
*myFloatConstant = 0x4C000000;
使用浮动:
float theActualFloat = *(float *) myFloatConstant;
我仍然想保留 -O3
,但它再次使用 .rodata
,因此可能的答案将包括 which optimization flag causes the floats to be placed in .rodata
,因为从 -O1
开始,这正在发生吗?
最好的情况是我可以在代码中使用浮点数 "normally" 加上最大优化,它们根本不会放在 .rodata
中。
我想 GCC
可能做的是通过混合数据和代码将浮点常量放在代码之间,从那个地方加载到浮点寄存器并继续。我相信这可以手动编写,但是如何让 GCC
做到这一点?强制每个变量的属性会导致上面的错误,但从技术上讲这应该是可行的。
使用 GCC 7.1.0 powerpc-eabi(Linux 下的交叉编译器)以下代码对我有效:
float test(void)
{
int x;
volatile float y;
float theActualFloat;
*(float *)&x = 1.2345f;
*(int *)&y = x;
theActualFloat = y;
return theActualFloat;
}
生成的汇编代码:
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
解释:
在 *(float *)&x = value
行中,您写入一个将由编译器优化的整数。编译器将执行不访问 .rodata
.
*(int *)&y = x
行无论如何都是纯整数运算。
由于 volatile
,theActualFloat = y
行无法优化,因此编译器必须将整数写入堆栈上的变量,并且必须从变量中读取结果。
我找到了另一个解决方案,它避免了 stack frame
创建和 .rodata
使用,但需要一个绝对内存地址来存储浮点数:
static inline volatile float *getFloatPointer(int address, float value) {
float *pointer = (float *) address;
*pointer = value;
return pointer;
}
它是这样使用的:
volatile float *myFloat = getFloatPointer(0x12345678, 30.f);
printf("%f", *myFloat);
重要的是不要创建局部 float
变量,只创建 volatile
指针,这样它就不会再次使用 .rodata
。