由于这是我发表stackoverflow的第一篇文章,我想感谢大家过去为我提供很多帮助的宝贵帖子。
我在Windows-7(64)上使用MinGW(gcc 4.4.0) - 更具体地说,我使用的是诺基亚Qt + MinGW,但Qt没有参与我的问题。
我需要在运行时找到地址和更重要的 - 我的应用程序的特定功能的长度,以便编码/解码这些功能并实现软件保护系统。
我已经找到了一个关于如何计算函数长度的解决方案,假设静态函数在源文件中一个接一个地放置,顺序放置在编译的目标文件中并随后在记忆。
不幸的是,只有使用选项“g ++ -O0”(优化级别= 0)编译整个CPP文件时才会出现这种情况。 如果我使用“g ++ -O2”(这是我的项目的默认值)编译它,编译器似乎重新定位了一些函数,因此计算的函数长度似乎是不正确的和负的(!)。
即使我在源文件中放入“#pragma GCC optimize 0”行,也会发生这种情况, 这应该相当于“g ++ -O0”命令行选项。
我认为“g ++ -O2”指示编译器执行一些全局文件级优化(某些函数重定位?),这是使用#pragma指令无法避免的。
您是否知道如何防止这种情况,而无需使用-O0选项编译整个文件? 或者:你知道在运行时找到函数长度的任何其他方法吗?
我为您准备了一个小例子,以及使用不同编译选项的结果,以突出显示案例。
// ===================================================================
// test.cpp
//
// Intention: To find the addr and length of a function at runtime
// Problem: The application output is correct when compiled with: "g++ -O0"
// but it's erroneous when compiled with "g++ -O2"
// (although a directive "#pragma GCC optimize 0" is present)
// ===================================================================
#include <stdio.h>
#include <math.h>
#pragma GCC optimize 0
static int test_01(int p1)
{
putchar('a');
putchar('\n');
return 1;
}
static int test_02(int p1)
{
putchar('b');
putchar('b');
putchar('\n');
return 2;
}
static int test_03(int p1)
{
putchar('c');
putchar('\n');
return 3;
}
static int test_04(int p1)
{
putchar('d');
putchar('\n');
return 4;
}
// Print a HexDump of a specific address and length
void HexDump(void *startAddr, long len)
{
unsigned char *buf = (unsigned char *)startAddr;
printf("addr:%ld, len:%ld\n", (long )startAddr, len);
len = (long )fabs(len);
while (len)
{
printf("%02x.", *buf);
buf++;
len--;
}
printf("\n");
}
int main(int argc, char *argv[])
{
printf("======================\n");
long fun_len = (long )test_02 - (long )test_01;
HexDump((void *)test_01, fun_len);
printf("======================\n");
fun_len = (long )test_03 - (long )test_02;
HexDump((void *)test_02, fun_len);
printf("======================\n");
fun_len = (long )test_04 - (long )test_03;
HexDump((void *)test_03, fun_len);
printf("Test End\n");
getchar();
// Just a trick to block optimizer from eliminating test_xx() functions as unused
if (argc > 1)
{
test_01(1);
test_02(2);
test_03(3);
test_04(4);
}
}
使用“g ++ -O0”编译时的(正确)输出:
======================
addr:4199344, len:37
55.89.e5.83.ec.18.c7.04.24.61.00.00.00.e8.4e.62.00.00.c7.04.24.0a.00.00.00.e8.42
.62.00.00.b8.01.00.00.00.c9.c3.
======================
addr:4199381, len:49
55.89.e5.83.ec.18.c7.04.24.62.00.00.00.e8.29.62.00.00.c7.04.24.62.00.00.00.e8.1d
.62.00.00.c7.04.24.0a.00.00.00.e8.11.62.00.00.b8.02.00.00.00.c9.c3.
======================
addr:4199430, len:37
55.89.e5.83.ec.18.c7.04.24.63.00.00.00.e8.f8.61.00.00.c7.04.24.0a.00.00.00.e8.ec
.61.00.00.b8.03.00.00.00.c9.c3.
Test End
使用“g ++ -O2”编译时的错误输出: (a)功能test_01 addr&amp; len似乎是正确的 (b)函数test_02,test_03具有负长度,
======================
addr:4199416, len:36
83.ec.1c.c7.04.24.61.00.00.00.e8.c5.61.00.00.c7.04.24.0a.00.00.00.e8.b9.61.00.00
.b8.01.00.00.00.83.c4.1c.c3.
======================
addr:4199452, len:-72
83.ec.1c.c7.04.24.62.00.00.00.e8.a1.61.00.00.c7.04.24.62.00.00.00.e8.95.61.00.00
.c7.04.24.0a.00.00.00.e8.89.61.00.00.b8.02.00.00.00.83.c4.1c.c3.57.56.53.83.ec.2
0.8b.5c.24.34.8b.7c.24.30.89.5c.24.08.89.7c.24.04.c7.04.
======================
addr:4199380, len:-36
83.ec.1c.c7.04.24.63.00.00.00.e8.e9.61.00.00.c7.04.24.0a.00.00.00.e8.dd.61.00.00
.b8.03.00.00.00.83.c4.1c.c3.
Test End
答案 0 :(得分:1)
即使我在源文件中放置了一个“#pragma GCC optimize 0”行,也会发生这种情况,该行应该等同于“g ++ -O0”命令行选项。
我不相信这是真的:它应该等同于将__attribute__((optimize(0)))
附加到随后定义的函数,这会导致使用不同的优化级别编译那些函数 。但是这不会影响顶层发生的事情,而命令行选项会这样做。
如果您真的必须做依赖于顶级订购的可怕事情,请尝试使用-fno-toplevel-reorder
选项。我怀疑将__attribute__((noinline))
添加到相关函数中也是一个好主意。