There is an array in ASM (already initialized), the C ++ function is called that sorts and returns an already sorted array. I wrote the code, but I get an error.

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 

Here I get this error:

mistake

    1 answer 1

    It is not directly related to what the assembler writes to you when compiling, but still here is a list of comments to your code:

    1. If you compile under Windows, then you do not need to initialize ds. If you can still compile the program, then it will safely fall when you try to overwrite the value in this register.
    2. You assume that the C ++ function takes a pointer to the beginning of the array in the edx register, but I wouldn't be so sure if I were you. It is better to explicitly set the calling convention for the SortMass function (for example, stdcall or fastcall), and pass parameters to it in accordance with the same agreement.
    3. In the C ++ part, the main function is not needed - your main function is in fact in the assembler part.
    4. sizeof from the pointer will give you the size of the pointer. Apparently, you are compiling into a 32-bit code, so you will have sizeof(m) 4. sizeof does not determine the size of the array passed by the pointer in a magical way, it simply determines the size of the argument passed to it. You need to pass along with the pointer to the beginning of the array to the function and its size, and use this size instead of sizeof .
    5. In the "sishnoy" function you take a pointer to an integer (at the beginning of the array), and in the assembler part you create an array of 7 bytes. Decide whether you need to create an array of dword-sized elements, which in your case will correspond to the int array in c ++, or vice versa, in the c ++ part, take a pointer to the char array (which corresponds to an array of bytes in the assembler).
    6. A piece starting with push ebp and ending with pop ebp is somehow completely off topic. Just a copied and pasted piece from some example, unrelated to the rest of the code. Just delete it.

    Addition about calling conventions.

    The C language supports several calling cdecl : cdecl , stdcall , fastcall , pascal . They differ in the way the arguments are passed (via registers or stack), the order of passing through the stack (reverse order for stcall and cdecl and forward for pascal ), and who aligns the stack (the code to be called or the calling code is stdcall or cdecl ). In fact, agreements are necessary for the calling code to put the arguments in exactly the place from which the called function will pick it up (well, so that the stack is properly aligned). All agreements allow you to change the pointer passed through the parameter through the transfer of a double pointer, but in fact you do not need this, because In your function, the pointer does not change, but the data is sorted by the pointer.

    Depending on the compiler used, the chosen level of optimization, the compiler may choose different calling conventions for the function. For the function used inside the "module" it does not matter much, because in this case, the compiler will agree on the way parameters are passed. But for functions accessible from outside, you need to explicitly set the agreement, call the function according to the same agreement.

    In your code, you pass a pointer to an array in the register, but it may turn out that the function will look for it on the stack, and find some garbage there. If suddenly the C ++ compiler wants to use the fastcall agreement, the function will most likely look for the first parameter in the ecx rather than edx (most likely because the fastcall agreement is not standardized, and it is better to use it for calls between modules compiled by one and same compiler). That's just to ensure that the function will look for the parameter where it is needed, just need to explicitly prescribe the calling conventions.

    • Thank you, 1. Made 2. These agreements cannot modify the pointer, and without it the program does not want to work 3. I used it just to check the code for errors 4. Added a parameter and a variable in asm 5. Corrected on dw 6. deleted - nait123321
    • @ nait123321, 2 - firstly, your function does not modify the pointer, but changes the data according to the pointer - sorts them, these are two completely different things; secondly, you can return the modified value of the pointer through the return ; third, you can change the pointer by passing a double pointer (respectively, the type of the argument must be an int ** ); fourth, in any case, if you do not explicitly indicate the calling convention, the compiler will choose one of the three according to its own “desire” - cdecl, stdcall, fastcall, it does not have much choice here. 5 - you need dd ("define dword") - insolor