Ошибка в C++ при обращении к dll (на асем)

Рейтинг: 3Ответов: 1Опубликовано: 02.03.2015

Здравствуйте форумчане! Помогите пожалуйста устранить ошибку... При выполнении программы всплывает ошибка:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention. после продолжения выполняет все правильно...

код на С++:

    # define N 100 // Размер массива
    # define a 1.2 // Начало отрезка
    # define b 2.8 // Конец отрезка

    using namespace std;
    typedef void (__stdcall *asmfunc)(float* ,float* ,int );
    void main()
    {
        asmfunc func;
        system("chcp 1251 > null");
        cout<<" Введите количество узлов: ";
        int n;
        cin>>n;
        float __declspec(align(16)) A[N],R[N];   //выравнивание массива 16
        double S=0.0;
        HMODULE hLib; 
        hLib = LoadLibrary(TEXT("xmm.dll")); 
    if (hLib != NULL)
        { 
            cout<<"Библиотека загружена!!!"<< endl;
        }

    func = (asmfunc)GetProcAddress(hLib, "asmfunc");
    if (!func)
        cout<< " Функция не найдена !!!"<< endl;
    else
        {
        A[0]=a;
        for(int i=1;i<n;A[i]=A[i-1]+(b-a)/n,++i);  //деление отрезка от а до b на n частей и запись отрезков в массив А
        func(A,R,n);                               //в массив R записывается масив А в квадрате
        for(int i=0;i<n;S+=R[i],++i);              // Суммирование массива R
        }
        cout<<"\n Сумма квадратов : "<<S<<endl;
        FreeLibrary(hLib);
        system("pause");
    }

библиотека на асеме: .586 ; разрешает непривилегированные ; команды Pentium .XMM ; разрешает команды SSE .MODEL FLAT, stdcall ; задает модель памяти PUBLIC asmfunc ; имя экспортируемой функции .CODE ; сегмент кода

_start@12:   ; точка входа в DLL
    mov eax,    1; надо вернуть ненулевое число в EAX   
    ret      ; очистить стек (передано три параметра)

asmfunc PROC ms1:DWORD, ms2:DWORD, ln:DWORD         ; заголовок функции

    mov eax,    [ln]    ;в eax - размер массивов
    mov edi,    [ms2]   ;в esi - адрес массива 2
    mov esi,    [ms1]   ;в edi - адрес массива 1
the_loop:
    movaps  xmm0,   [esi]       ;поместить в регистр xmm0
                                ;4 элементов массива 1
    movaps  xmm1,   [esi]       ;поместить в регистр xmm1
                                ;4 элементов массива 1
        mulps   xmm0,   xmm1        ;перемножение хмм0*хмм1 и запись в хмм0 (получаем квадрат массива)

    movaps [edi], xmm0  ; запись результатов в массив №2 (4 элемента)
    add esi,    16      ;следующие 4-ре элемента
    add edi,    16      ;следующие 4-ре элемента
    sub eax,    4       ;уменьшить значения счетчика
    jnz short   the_loop    ;конец цикла?
    emms

    ret 12
asmfunc ENDP            ; завершение функции
 END    _start@12    ; точка выхода из DLL

Спасибо!

Ответы

▲ 3Принят
  1. Не совсем по вопросу, скорее по стилю, но пожалуйста, не делайте так, распишите в нормальный цикл:

    for(int i=1;i<n;A[i]=A[i-1]+(b-a)/n,++i);
    ...
    for(int i=0;i<n;S+=R[i],++i); 
    
  2. Соглашение stdcall подразумевает, что функция оставит неизменными, в частности, регистры edi и esi. Нужно в начало функции добавить push edi и push esi, а в конце перед ret добавить pop esi и pop edi (порядок обратный тому, в каком заталкивали, так как стек).