Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Вызов функции извне


Автор: ParaPik 16.4.2011, 14:03
Есть код:
Код

WORD __declspec(dllexport) __cdecl RunMTest(const wchar_t * str)
{
    HANDLE fin = CreateFile(str, GENERIC_READ, FILE_SHARE_READ, nullptr,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (GetLastError() == ERROR_FILE_NOT_FOUND)
        return -1;
    typedef unsigned char byte;
    vector<byte> func;    
    char bt = 0;
    DWORD numRead = 0;
    while (ReadFile(fin, &bt, 1, &numRead, nullptr))
    {
        if (numRead == 0)
            break;
        func.push_back(bt);
    }
    CloseHandle(fin);
    
    
    void * _p = func.data();
    times.push_back(0);
    DWORD ID = times.size() - 1;
    SetTimer(nullptr, ID, USER_TIMER_MINIMUM, TimerFunc);
    __asm
    {
        push edx
        mov edx, _p // здесь вылетает ошибка Access Violation
        call edx
        pop edx
    }
    
    KillTimer(0, ID);
    return times[ID];    
}


Не могу разобраться, почему возникает эта ошибка. В файле, который считывает функция, содержит откомпилированную инструкцию RET(для пробы), т.е. 1 байт. Помогите понять, в чем дело.

Автор: xvr 16.4.2011, 18:12
В x86 не всякие данные можно исполнить. То, что исполняется должно быть помещено в исполняемый сегмент.
Смотри http://ru.wikipedia.org/wiki/Data_Execution_Prevention

Автор: Dem_max 16.4.2011, 18:51
хорошим прявилом программирования является не использование asm вставок 

Автор: ParaPik 17.4.2011, 11:03
А есть какой-нибудь другой способ запустить на исполнение код из файла? При компиляции в Visual Studio этот код не хочет работать, но если откомпилировать в C++Builder, то все нормально.(когда-то давно это делал, а сейчас только решил использовать этот код) Не хочется ради одной функции ставить другую IDE.
Цитата

хорошим прявилом программирования является не использование asm вставок

Далеко не во всех случаях. Простой пример: перевести число в строку в двоичном виде. Код, решающий эту проблему и написанный самостоятельно на asm, будет в разы быстрее нежели аналог, например, на C.

Автор: borisbn 17.4.2011, 13:34
Цитата(ParaPik @  17.4.2011,  11:03 Найти цитируемый пост)
од, решающий эту проблему и написанный самостоятельно на asm, будет в разы быстрее нежели аналог, например, на C.

ОМГ, ещё один "мистер быстрее компилятора"...
Представить доказательство, что код на Си++ (на MSVC 2010, например) медленнее твоего велосипеда - религия не позволяет ?

Автор: ParaPik 17.4.2011, 14:27
А я разве могу, используя средства C++, узнать напрямую состояние флага CF? Это процедура перевода будет использовать только команды shr и jc. Используя C++, максимум, что я смогу использовать, это инструкцию div, которая медленнее shr. Первый вариант будет быстрее. 
Вот на asm:
Код

mov eax, var
@label:
cmp eax, 0
jz @exit
shr eax, 1
jc @one
mov cl, 0
jmp @func
@one
mov cl, 1
@func:
call Insert
jmp @label
@exit:

Вариант на C++ будет длиннее.

Автор: borisbn 17.4.2011, 14:36
ParaPik, не знание (твоё) Си++ не освобождает от ответственности...
Код

for ( int i = 0; i < sizeof( int ) * 8; ++i ) {
    Insert( var & 1 ); // это твой call Insert
    var >>= 1; // вот это - твой shr
}

а теперь давай спорить на пиво, что твой вариант медленнее этого, скомпилированного последней версией gcc или MSVC 2010 с опцией /O2


можно непонятнее, но ещё короче и, наверное, быстрее
Код

for ( ; var; var >>= 1 )
    Insert( var & 1 );

Автор: ParaPik 17.4.2011, 17:46
1) Я схватил первый попавшийся пример(алгоритм его решения на C++ был не самый лучший).
2) Рассмотрел его с отключенной оптимизацией. Ясен пень, что с включенной оптимизацией компилятор всегда заметит то, чего не смог заметить человек.
3) 
Цитата

не знание (твоё) Си++ не освобождает от ответственности...

Не утверждай того, чего не знаешь. И пробуй иногда для себя отдираться от сторонних оптимизаторов. 
4) Не спорю, в моем варианте тоже есть моменты, которые можно оптимизировать. 
5) И у кого-то проблемы с восприятием текста. Какая проблема рассматривается в теме? Единственный, кто ответил, в чем проблема, был xvr. Жаль, что он не предложил альтернативный вариант решения. Остальная болтовня о том, нужны ли asm вставки или нет, вообще, честно говоря, не относится к теме. Поэтому если есть проблемы с восприятием текста или нет дельного совета, просьба - НЕ ЗАСОРЯТЬ тему.

Автор: borisbn 17.4.2011, 19:07
Цитата(ParaPik @  17.4.2011,  17:46 Найти цитируемый пост)
Не утверждай того, чего не знаешь. 

просто делаю выводы. из этого
Цитата(ParaPik @  17.4.2011,  14:27 Найти цитируемый пост)
Используя C++, максимум, что я смогу использовать, это инструкцию div


Цитата(ParaPik @  17.4.2011,  17:46 Найти цитируемый пост)
И пробуй иногда для себя отдираться от сторонних оптимизаторов.

я, какбэ, сам знаю, что мне пробовать, а что нет.


по теме: см. функцию http://msdn.microsoft.com/ru-ru/library/aa366898(v=VS.85).aspx
с третьим параметром PAGE_EXECUTE_READWRITE

Автор: ParaPik 17.4.2011, 19:34
А вот теперь спасибо. Все работает. smile 

Автор: xvr 17.4.2011, 19:51
Цитата(ParaPik @  17.4.2011,  17:46 Найти цитируемый пост)
Жаль, что он не предложил альтернативный вариант решения. 

С VirtualProtect вы уже сами разобрались, а по поводу asm вставки - она тут лишняя
Код

    void * _p = func.data();
/*
    __asm
    {
        push edx
        mov edx, _p // здесь вылетает ошибка Access Violation
        call edx
        pop edx
    }
*/
 (  ( void (*)() ) _p )   (); // Это ваша asm вставка на голом С


Автор: ParaPik 17.4.2011, 20:02
Спасибо за ответ, xvr. Я знаю, что есть аналог asm-вставки на C, который вы и предложили. Здесь оно, все равно, непринципиально.
Поправьте меня, если я немного не так понял, xvr: вы придрались к asm-вставке, потому что код не должен быть привязан к командам конкретной машины(т.е. чтобы код был привязан только к C++ компилятору)?

Автор: xvr 18.4.2011, 08:29
Цитата(ParaPik @  17.4.2011,  20:02 Найти цитируемый пост)
Поправьте меня, если я немного не так понял, xvr: вы придрались к asm-вставке,

К asm вставке прелирался не я, а Dem_max. Но в общем и целом я с ним согласен - asm вставка оправданна только тогда, когда ее действие нельзя выполнить эквивалентным по объему С/С++ кодом.
Это может быть и доступ к недоступным с С уровня регистрам, и оптимизация по скорости критичных участков программы, но явно не банальный вызов процедуры по указателю. Язык С предоставляет такой сервис штатно  smile 

Автор: 500mhz 18.4.2011, 09:48
Код

 (  ( void (*)() ) _p )   (); // Это ваша asm вставка на голом С


а вы листинг асмовский ее видели?

Автор: borisbn 18.4.2011, 10:06
500mhz, 
Код

char * _p = 0;
(  ( void (*)() ) _p )   ();

Код

; 7    : char * _p = 0;
    mov    DWORD PTR __p$[ebp], 0
; 8    : (  ( void (*)() ) _p )   ();
    call    DWORD PTR __p$[ebp]

и что ?

Автор: ParaPik 18.4.2011, 14:04
xvr, я все-таки заменил asm вариант на стандартный сишный. Я соглашусь, что оно здесь не нужно. Ну, если только для красоты оставить... smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)