【问题标题】:How to find the address & length of a C++ function at runtime (MinGW)如何在运行时查找 C++ 函数的地址和长度(MinGW)
【发布时间】:2011-07-17 01:59:06
【问题描述】:

由于这是我在 stackoverflow 上的第一篇文章,我要感谢大家的宝贵文章,这些文章在过去对我有很大帮助。

我在 Windows-7(64) 上使用 MinGW (gcc 4.4.0) - 更具体地说,我使用诺基亚 Qt + MinGW,但 Qt 不涉及我的问题。

我需要在运行时找到我的应用程序的特定功能的地址和(更重要的是)长度,以便对这些功能进行编码/解码并实现软件保护系统。

我已经找到了一个关于如何计算函数长度的解决方案,通过假设静态函数在源文件中一个接一个地放置,逻辑上也依次放置在编译的目标文件中,然后在记忆。

不幸的是,只有当整个 CPP 文件使用以下选项编译时才是正确的:“g++ -O0”(优化级别 = 0)。 如果我使用“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”编译时的(正确)输出:

[注意所有函数末尾的'c3'字节(=汇编'ret')]

======================
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 & len 似乎正确 (b) 函数 test_02、test_03 的长度为负数,

和乐趣。 test_02 长度也不正确。

======================
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

【问题讨论】:

    标签: gcc mingw function-pointers compiler-optimization


    【解决方案1】:

    即使我在源文件中添加了“#pragma GCC optimize 0”行,也会发生这种情况,这应该等同于“g++ -O0”命令行选项。

    我不相信这是真的:它应该相当于将__attribute__((optimize(0))) 附加到随后定义的函数,这会导致这些函数以不同的优化级别进行编译。但这不会影响顶层发生的事情,而命令行选项会。

    如果您真的必须做依赖顶级排序的可怕事情,请尝试-fno-toplevel-reorder 选项。而且我怀疑将__attribute__((noinline)) 添加到相关函数中也是一个好主意。

    【讨论】:

    • Matthew 非常感谢,-fno-toplevel-reorder 似乎可以解决我的问题 :-)
    猜你喜欢
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 2014-07-12
    • 2013-06-05
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多