Вызов С++ функции из ассемблера

472
28 мая 2017, 22:35

Здравствуйте, есть массив в ASM(уже инициализированный), вызывается функция С++ которая сортирует и возвращает уже отсортированный массив. Написал код, но получаю ошибку. Гуглил, применял их решения - ничего не помогло. source.cpp

#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
    return 0;
}
extern "C" int *SortMass(int* m)
{
    for (int i = sizeof(m) - 1; i >= 1; i--)
        for (int j = 0; j < i; j++)
        {
            if (m[j] > m[j + 1])
            {
                int foo = m[j];
                m[j] = m[j + 1];
                m[j + 1] = foo;
            }
        }
    for (int i = 0; i < sizeof(m);++i)
        cout << m[i] << endl;
    return m;
}

ASM

.386 ;
.model flat
extern _SortMass : proc
.data
    mas db 12, 2, 7, 3, 2, 1, 21
.code
    mov     ax,@data
    mov     ds,eax
    mov edx, offset mas
    call _SortMass
    push    EBP
    mov     EBP, ESP      
mov eax,[ebp+4]     ; get the address of the array
mov ebp, eax        ; BP now points to the array
mov eax, [ebp]      ; get value of first element
add eax,[ebp+2]     ;   add remaining elements
add eax,[ebp+4]
pop EBP
ret

end
END

Информация о ошибках: введите сюда описание ссылки

Answer 1

Не связано напрямую с тем, что пишет вам ассемблер при компиляции, но все же вот список замечаний к вашему коду:

  1. Если вы компилируете под Windows, то вам не нужно инициализировать ds. Если вам таки удастся скомпилировать программу, то она благополучно упадет при попытке перезаписать значение в этом регистре.
  2. Вы предполагаете, что C++ функция принимает указатель на начало массива в регистре edx, но я на вашем месте не был бы так уверен. Лучше явно задать соглашение вызова для функции SortMass (например, stdcall или fastcall), и в соответствии с этим же соглашением передавать ей параметры.
  3. В С++ части не нужна функция main - ваша функция main по факту находится в ассемблерной части.
  4. sizeof от указателя даст вам размер указателя. Судя по всему, компилируете вы в 32-битный код, поэтому sizeof(m) у вас будет равен 4. sizeof не определяет магическим способом размер массива, переданного по указателю, он просто определяет размер переданного ему аргумента. Вам нужно вместе с указателем на начало массива также передавать в функцию и его размер, и использовать этот размер вместо sizeof.
  5. В "сишной" функции вы принимаете указатель на целое число (на начало массива), а в ассемблерной части создаете массив из 7 байт. Определитесь - вам либо нужно создавать массив элементов размера dword, что в вашем случае будет соответствовать массиву int в c++, либо наоборот, в c++ части принимать указатель на массив char (что соответствует массиву байт на ассемблере).
  6. Кусок начиная с push ebp и заканчивая pop ebp как-то совсем не в тему. Просто скопированный и вставленный кусок из какого-то примера, никак не связанный с остальным кодом. Просто удалите его.

Дополнение по поводу соглашений вызова.

Язык Си поддерживает несколько соглашений вызова: cdecl, stdcall, fastcall, pascal. Различаются они способом передачи аргументов (через регистры или стэк), порядком передачи через стэк (обратный порядок для stcall и cdecl и прямой для pascal), и кто выравнивает стэк (вызываемый код или вызывающий код - stdcall или cdecl). По факту соглашения нужны для того, чтобы вызывающий код клал аргументы именно в то место, откуда его потом заберет вызываемая функция (ну и чтобы стэк был правильно выровнен). Все соглашения позволяют менять переданный через параметр указатель - через передачу двойного указателя, но это по факту вам не нужно, т.к. у вас в функции указатель не меняется, а просто происходит сортировка данных по указателю.

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

В вашем коде вы передаете указатель на массив в регистре, но может оказаться, что функция будет искать его в стеке, а найдет там какой-то мусор. Если же вдруг компилятор С++ захочет использовать соглашение fastcall, то первый параметр функция будет искать скорее всего в регистре ecx, а не edx (скорее всего - потому что соглашение fastcall не стандартизовано, и лучше его использовать для вызовов между модулями, скомпилированными одним и тем же компилятором). Вот как раз для того чтобы гарантировать то, что функция будет искать параметр там где нужно, как раз и нужно явно прописывать соглашения вызова.

READ ALSO
Алгоритм простого числа

Алгоритм простого числа

Может кто нибудь подсказать, что не так с этим алгоритмом? Проблема в том, что при запуске некоторые числа отображаются в командной строке...

204
Двухмерный массив как параметр функции c++

Двухмерный массив как параметр функции c++

Как передать двухмерный массив в функцию как параметр? пытался сделать ссылку, но выдает ошибкуКод программы ниже

368
Что такое мультисписок?

Что такое мультисписок?

Я долго всматривался в эту картинку и пытался понять, что же такое мультисписок, но до сих пор не понимаю, как это реализовать

388
помогите перевести код с С++ на С#

помогите перевести код с С++ на С#

Задача по структурам поля № авиарейса время полета время прилета направление марка самолета расстояние вывести данные об авиарейсе с максимальной...

294