2

以下代码使用标志 Od、O1 按预期工作,但使用 O2、Ox 失败。任何想法为什么?

编辑:“失败”是指该函数什么都不做,似乎只是返回。

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);
    }
}
4

2 回答 2

3

这可能是因为您的编译器没有在更高的优化级别上使用特定的帧指针寄存器,这释放了一个额外的通用寄存器。

这意味着编译器pStack使用堆栈指针的偏移量访问局部变量。在堆栈指针被调整后,它无法正确执行此操作pushad-pushfd它不期望堆栈指针发生变化。

为了解决这个问题,您不应该在这些asm语句之后放置任何 C 代码,直到堆栈指针被正确恢复:从 firstpushadpopador的所有内容都startThread()应该在汇编程序中。这样,您可以加载局部变量的地址并确保访问正确完成。

于 2011-11-11T12:12:12.273 回答
2

当您使用内联汇编程序时,您可能想看看在使用各种 -Ox 选项编译代码时,代码是如何(或是否)真正修改的。在你的二进制文件上试试这个:

objdump -s your_program

它提供了一堆代码,但找到相应的代码部分不应该那么难(搜索您的程序集或函数名称)。

顺便说一句,我被告知,内联汇编不能很好地进行大量优化,因此我倾向于将汇编程序例程分离到 .S 文件中。

于 2011-11-12T22:26:11.033 回答