Флаги компилятора изменяют поведение кода (O2, Ox) - PullRequest
2 голосов
/ 11 ноября 2011

Следующий код работает как ожидается с флагами Od, O1, но не работает с O2, Ox. Есть идеи почему?

edit: под "fails" я имею в виду, что функция ничего не делает и, кажется, просто возвращает.

void thread_sleep()
{
    listIterator nextThread = getNextThread();
    void * pStack = 0;
    struct ProcessControlBlock * currPcb = pPCBs->getData(currentThread);
    struct ProcessControlBlock * nextPcb = pPCBs->getData(nextThread);

    if(currentThread == nextThread)
    {
        return;
    }
    else
    {
        currentThread = nextThread;
        __asm pushad            // push general purpose registers
        __asm pushfd            // push control registers
        __asm mov pStack, esp   // store stack pointer in temporary

        currPcb->pStack = pStack;   // store current stack pointer in pcb
        pStack = nextPcb->pStack;   // grab new stack pointer from pcb

        if(nextPcb->state == RUNNING_STATE)// only pop if function was running before
        {
            __asm mov esp, pStack       // restore new stack pointer
            __asm popfd
            __asm popad;
        }
        else
        {
            __asm mov esp, pStack       // restore new stack pointer
            startThread(currentThread);
        }
    }
}

// После реализации предложений: (все еще не работает)

listIterator nextThread = getNextThread();
struct ProcessControlBlock * currPcb = pPCBs->getData(currentThread);
struct ProcessControlBlock * nextPcb = pPCBs->getData(nextThread);
void * pStack = 0;
void * pNewStack = nextPcb->pStack; // grab new stack pointer from pcb
pgVoid2 = nextPcb->pStack;

if(currentThread == nextThread)
{
    return;
}
else
{
    lastThread = currentThread; // global var
    currentThread = nextThread;


    if(nextPcb->state == RUNNING_STATE)// only pop if function was running before
    {
        __asm pushad                // push general purpose registers
        __asm pushfd                // push control registers
        __asm mov pgVoid1, esp      // store stack pointer in temporary
        __asm mov esp, pgVoid2      // restore new stack pointer
        __asm popfd
        __asm popad;

        {
            struct ProcessControlBlock * pcb = pPCBs->getData(lastThread);
            pcb->pStack = pgVoid1; // store old stack pointer in pcb
        }
    }
    else
    {
        __asm pushad                // push general purpose registers
        __asm pushfd                // push control registers
        __asm mov pgVoid1, esp  // store stack pointer in temporary
        __asm mov esp, pgVoid2      // restore new stack pointer

        {
            struct ProcessControlBlock * pcb = pPCBs->getData(lastThread);
            pcb->pStack = pgVoid1; // store old stack pointer in pcb
        }
        startThread(currentThread);
    }
}

Ответы [ 2 ]

3 голосов
/ 11 ноября 2011

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

Это означает, что компилятор обращается к локальной переменной pStack, используя смещение от указателя стека. Он не может сделать это правильно после того, как указатель стека был настроен pushad и pushfd - он не ожидает изменения указателя стека.

Чтобы обойти это, вы не должны ставить код C после этих операторов asm до тех пор, пока указатель стека не будет правильно восстановлен: все от первого pushad до popad или startThread() должно быть в ассемблере. Таким образом, вы можете загрузить адрес локальных переменных и убедиться, что доступ сделан правильно.

2 голосов
/ 13 ноября 2011

Поскольку вы используете встроенный ассемблер, вы, вероятно, захотите узнать, как (или есть) код действительно изменяется, когда он компилируется с различными опциями -Ox.Попробуйте это в своем двоичном файле:

objdump -s your_program

Это дает кучу кода, но найти соответствующий раздел кода не должно быть так сложно (поиск вашей сборки или имена функций).

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

...