Как найти адрес и длину функции C ++ во время выполнения (MinGW) - PullRequest
0 голосов
/ 17 марта 2011

Поскольку это мой первый пост в stackoverflow, я хочу поблагодарить вас всех за ваши ценные посты, которые мне очень помогли в прошлом.

Я использую MinGW (gcc 4.4.0) в Windows-7 (64) - точнее, я использую Nokia 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 кажется правильной (б) функции 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

1 Ответ

1 голос
/ 18 марта 2011

Это происходит, даже если я помещаю строку "#pragma GCC optimize 0" в исходный файл, который должен быть эквивалентом опции командной строки "g ++ -O0".

Я не верю, что это правда: предполагается, что это эквивалентно присоединению __attribute__((optimize(0))) к последующим определенным функциям, что приводит к компиляции этих функций с другим уровнем оптимизации. Но это не влияет на то, что происходит на верхнем уровне, в то время как опция командной строки делает это.

Если вы действительно должны делать ужасные вещи, которые зависят от упорядочивания на высшем уровне, попробуйте опцию -fno-toplevel-reorder. И я подозреваю, что было бы неплохо добавить __attribute__((noinline)) к рассматриваемым функциям.

...