2013-04-19 2 views
0

У меня есть программа с функцией, выполненной только с встроенной сборкой.Ошибка встроенной сборки только в версии

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

Вся моя программа работает очень хорошо в режиме отладки, но когда я проверить его в версии, у меня есть эта ошибка:

SomeThing.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x0A4B2FFC). 

Вот моя сборка функция:

__declspec(naked) void Player_dummyFunction(dvrFunction* iFunc) 
{ 
    __asm push ebp 
    __asm mov ebp,esp 
    __asm sub esp,0C0h 
    __asm push ebx 
    __asm push esi 
    __asm push edi 
    __asm lea edi,[ebp-0C0h] 
    __asm mov ecx,30h 
    __asm mov eax,0CCCCCCCCh 
    __asm rep stos dword ptr es:[edi] 

    /* Need the number of params. */ 
    __asm mov ecx, dword ptr [iFunc]   /* Use the calling convention of VC */ 
    __asm call dvrFunction::GetParamsNumber  /* this->m_ParamsData.size() */ 

    __asm mov edx, eax    /* Save the return value */ 

    __asm cmp edx, 0    /* Condition to know if the GL function has params (edx == 0) */ 
    __asm jz body     /* Jump to the body label if the previous condition is true */ 

push_loop: 
    /* Push the parameters in the reverse order on the stack */ 
    __asm mov ecx, dword ptr [iFunc]    /* Another use of the calling convention */ 
    __asm push edx 
    __asm call dvrFunction::GetParamsAddress  /* this->m_ParamsData[i]->GetAddress() */ 

    __asm push [eax]    /* Push the dereferenced address (the value) on the stack */ 

    /* edx is automatically decremented by GetParamsAddress */ 
    __asm cmp edx, 0    /* Is edx == 0 ? */ 
    __asm jnz push_loop    /* If no, go back push_loop label */ 

body: 
    __asm mov ecx, dword ptr [iFunc]     /* Use the thiscall convention */ 
    __asm call dvrFunction::GetCName     /* Call GetCName to have a const char* */ 

    __asm push eax          /* Push the name into the stack */ 
    __asm lea ecx, g_PlatBuiltin      /* Use another convention for the structs */ 

    __asm call [ecx]g_PlatBuiltin.wglGetProcAddress  /* Call the real wglGetProcAddress to have the pointer to the GL function */ 
    __asm mov ecx, eax         /* Save the result -> TODO Is this operation needed ? */ 

    __asm call ecx          /* Call the original open GL function */ 

    __asm pop edi 
    __asm pop esi 
    __asm pop ebx 
    __asm add esp,0C0h 
    __asm cmp ebp,esp 
    //__asm call __RTC_CheckEsp (0125114Fh) 
    __asm mov esp,ebp 
    __asm pop ebp 

    __asm ret           /* Call the ret asm command */ 
} 
+0

Из-за оптимизации программа может не иметь указателя кадра. Могут также произойти и другие изменения в макете стека. Я предлагаю вам позволить компилятору обрабатывать стек (с аргументами и локальными переменными) и делать только самые необходимые необходимые вещи в ассемблере (если нужно вообще!).Вы действительно измерили производительность вашей функции ассемблера по сравнению с тем, что было сделано на C++? С оптимизацией и без нее? –

+0

Я не читал код, но какой компилятор вы используете и каковы параметры оптимизации (на выходе и в режиме отладки)? – fstamour

+0

@JoachimPileborg Спасибо, может быть, я могу позволить компилятору сделать пролог и эпилог, но другие вещи должны быть сделаны в сборке ... –

ответ

1

На самом деле это не ответ, но код в комментариях становится очень грязным, а код ассемблера еще хуже, поскольку он полагается на новые строки для форматирования больше, чем C/C++.

__asm lea edi,[ebp-0C0h] 
__asm mov ecx,30h 
__asm mov eax,0CCCCCCCCh 
__asm rep stos dword ptr es:[edi] 

Это код «режим отладки», и вы действительно не должны этого делать в режиме деблокирования. На самом деле, я уверен, что большая часть эпилога и прологового кода вовсе не нужна для вашей функциональности - это просто «отладочный» материал.

Теперь для чего-то, что МОЖЕТ быть ответом: У меня такое ощущение, что авария вызвана GetParamsNumber, возвращая большее число в режиме без отладки, чем в режиме отладки. Я абсолютно не уверен в этом, это просто то, что имеет для меня большую ценность. Или, возможно, GetParamsNumber возвращает что-то НЕГАТИВНОЕ?

Ваш код также полагается на edx, который не изменяется на GetParamsAddress, что может быть неверно? В частности, он может ИЗМЕНИТЬ на основе режима оптимизации.

+0

Правильно для ответа, я только что увидел, что мой edx просто ложный после вызова GetParamsAddress. Я решил, что добавив pop edx после вызова функции. Я знаю, что эпилог и пролог не нужны, но эффективно я добавил его, потому что я изучал все возможности, которые могут решить это :-) Но спасибо вам за помощь. –

+0

Для эффективности вы можете попытаться использовать регистр, который является «спасением», например EDI или ESI. [Но тогда вам нужно нажать этот регистр при запуске вашего кода, но он сохраняет код в цикле] –

+0

Спасибо за совет. Я это сделаю. –

0

Попробуйте с добавлением/Oy- в выпуске

и проверить другие варианты оптимизации: msdn

+0

Просто сделал это, но у меня такая же проблема. Добавив опцию оптимизации (/ O1) для отладки, у меня тоже проблема. Но в режиме отладки он указывает линию сразу после GetParamsAddress: 'push [eax]'. –

+0

Вы можете попытаться отлаживать (с/O1) по очереди, чтобы увидеть, что находится в eax в данный момент .. и попытайтесь понять, является ли это правильным значением. (Всегда интересно отлаживать сборку -_-) – fstamour

0

Мое предположение, что конвейерная обработка запускается в некоторый код после инструкции ret. Я вижу, что ваш стек восстановлен достаточно тщательно, над его нормальными потребностями. (В самом деле, что если некоторые из этих функций развращает EBP Комментарий __asm ​​мов особ, EBP?) Вот что я думаю, что должно быть судимым в различных комбинациях:

  • Добавить 16 nop с после окончательного ret.
  • Капля esp восстановление. // __asm mov esp,ebp
  • Окунитесь в код с опусканием указателя стека, чтобы, если какой-то код слишком сильно перевернулся, верх не будет поврежден: (esp save here) sub esp,1000, код здесь, mov esp,ebp (при условии, что у вас есть восстановление стопки на месте).
  • Переместить стек, восстанавливающий материал, __asm push ebp
    __asm mov ebp,esp
    , позже __asm mov esp,ebp
    __asm pop ebp
    /внутри/ваш регистр восстанавливает материал. Если в вашем коде поврежден стек, ваш восстанавливающий код не сохранит ваши регистры esi, edi и ebx, как сейчас.
  • Прокомментируйте свои вызовы функций, чтобы узнать, какая функция искажает его, а затем постепенно узнайте, как восстановить предыдущее состояние.
+0

Я вполне уверен, что это не так. x86 - это согласованная архитектура, а это означает, что инструкции, зависящие от других инструкций, останавливаются до тех пор, пока их зависимости не будут завершены. Вы можете писать все, что вам нравится, в любом порядке, который дает правильный результат в x86, и он будет делать то, что вы ожидаете [с учетом ошибок процессора, но я на 100% уверен, что это не ошибка процессора). Чем больше я смотрю на это, у меня такое ощущение, что это «регистр использования после того, как он используется кем-то другим». –

Смежные вопросы