Странная декомпиляция при использовании g cc с разной оптимизацией - PullRequest
4 голосов
/ 18 февраля 2020

Я работаю на linux 5.4.18-1-MANJARO с g cc версия 9.2.0 (G CC)

Имя файла: a. c

#include<stdio.h>

int
main(void) {
    int a;

    scanf("%d", &a);

    if (a < 5 || a > 6)
        puts("fail");
    else
        puts("succeed");
}

Затем я запускаю:

gcc a.c -O0 -o a.out
gcc a.c -O1 -o b.out

Я декомпилирую a.out с помощью r2 и получаю это

undefined8 main(void)
{
    undefined8 uVar1;
    int64_t in_FS_OFFSET;
    int32_t var_ch;
    int64_t canary;

    canary = *(int64_t *)(in_FS_OFFSET + 0x28);
    sym.imp.__isoc99_scanf(0x2004, &var_ch);
    if ((var_ch < 5) || (6 < var_ch)) {
        sym.imp.puts("fail");
    } else {
        sym.imp.puts("succeed");
    }
    uVar1 = 0;
    if (canary != *(int64_t *)(in_FS_OFFSET + 0x28)) {
        uVar1 = sym.imp.__stack_chk_fail();
    }
    return uVar1;
}

Это то, что я ожидал.

Но когда я декомпилировал b.out, я получил

undefined8 main(void)
{
    undefined8 uVar1;
    undefined8 extraout_RDX;
    int64_t iVar2;
    int32_t *piVar3;
    uint32_t uVar4;
    int64_t in_FS_OFFSET;
    int32_t iStack20;
    int64_t iStack16;

    iStack16 = *(int64_t *)(in_FS_OFFSET + 0x28);
    piVar3 = &iStack20;
    sym.imp.__isoc99_scanf(0x2004, piVar3);
    if (iStack20 - 5U < 2) {
        uVar4 = 0x200c;
        sym.imp.puts("succeed");
    } else {
        uVar4 = 0x2007;
        sym.imp.puts("fail");
    }
    if (iStack16 != *(int64_t *)(in_FS_OFFSET + 0x28)) {
        sym.imp.__stack_chk_fail();
        sym._init();
        iVar2 = 0;
        do {
            uVar1 = (**(code **)(segment.LOAD3 + iVar2 * 8))((uint64_t)uVar4, piVar3, extraout_RDX);
            iVar2 = iVar2 + 1;
        } while (iVar2 != 1);
        return uVar1;
    }
    return 0;
}

, который, кажется, только проверяет, если iStack20 <7, и b.out работает нормально. </p>

Я не понимаю, как это работает .

1 Ответ

4 голосов
/ 18 февраля 2020

Здесь используется целочисленное занижение. Операция

iStack20 - 5U

выполняется без знака из-за неявных правил преобразования, когда два операнда различаются по типу (C стандарт 6.3.1.8 (1)):

В противном случае [подпись отличается] , если операнд с целым типом без знака имеет ранг, больший или равный рангу типа другого операнда, то операнд с целым типом со знаком преобразуется к типу операнда с целым типом без знака.

Так, если iStack20 равен <5, то результат будет очень большим (где-то около <code>UINT_MAX), следовательно, сравнение

iStack20 - 5U < 2

будет ложным. Если iStack20 равно> 6, то результат все равно будет больше 2. Таким образом, программа logi c сохраняется.

...