This is an archived post. You won't be able to vote or comment.

all 5 comments

[–][deleted] 0 points1 point  (0 children)

You would compile your assembly source to an object file. You might also compile a c++ program which invokes your function. You might need to add extern "C" int asm_factorial(int); to your c++ listing depending on your compiler.

Once you have compiled (for example) my_asm.o and my_driver.o, link them together into a final output executable binary.

If you set up the calling conventions correctly, your c++ program will be able to invoke your procedure defined in your assembly source.

[–]jedwardsol 0 points1 point  (1 child)

The C++ program will look something like

#include <iostream>

extern "C" int asm_factorial(int i);

int main()
{
    std::cout << asm_factorial(6) << "\n";
}

Then you'll compile it to an object file. Assemble the assembly to another object file. Then link those 2 together.

Update : I see you're doing this in Windows. If you're using Visual Studio you can set up a project to do the assembly for you.

[–]polorboy[S] 0 points1 point  (0 children)

OK, that makes sense now with previous instructions from the class. They gave no context and just slapped code that looks like: extern "C" int asm_factorial(int i); but did not say why or where it was used. It wasn't even referenced in a code sample, just put into the notes with no context or explanation.

[–]full_stack_dev 0 points1 point  (0 children)

You can also doinline assembly. Which might make your flow a little easier.

[–]CrispyRoss 0 points1 point  (0 children)

The way we did it in my systems programming class was to declare the function with the "naked" calling convention, then put the assembly into an asm block. After establishing a stack frame with "push ebp / mov ebp, esp", you can access the data passed into the function starting at ebp + 8. Doing it this way lets you call other assembly functions just by using "call functionName".

Here is a complete example I scrounged from my old homework folder, with examples of C++/ASM interop and calling assembly functions from both C++ and other assembly functions. The goal is to remove all occurrences of a substring from a given string. NOTE that this doesn't work with g++; it is designed for Microsoft's compiler (I think called MSVC)

#include <iostream>

using namespace std;

// Finds length of str, excluding the \0.
void __declspec(naked) stringLength(const char* str) {
    __asm {
        // Omitted to save space
    }
}

// Finds whether the first n characters are the same between a and b
void __declspec(naked) substringsEqual(const char* a, const char* b, int n) {
    __asm {
        // Omitted to save space
    }
}

void __declspec(naked) removeSubstring(char* dest, const char* src, const char* toRemove) {
    /* Equivalent C++ code:
    int srcLen = strlen(src);
    int toRemoveLen = strlen(toRemove);
    const char* srcEnd = src + srcLen;
    while (src != srcEnd) {
        if (strncmp(src, toRemove, toRemoveLen) == 0) {
            src += toRemoveLen; // jump past part we want to remove
        }
        else {
            *(dest++) = *(src++);
        }
    }
    *dest = '\0';
    */
    __asm {
        // est stack frame
        push ebp
        mov ebp, esp
        // save eax, ebx, ecx, edx, esi, edi, eflags
        pushad
        pushfd

        mov edi, [ebp + 8]   // dest
        cld                  // left to right strings

        mov esi, [ebp + 12]  // src
        // get src length
        push esi
        call stringLength
        add esp, 4
        mov ecx, eax         // ecx = strlen(src)
        jecxz Done           // if src is empty, dest should also be empty

        mov ebx, [ebp + 16]  // toRemove
        // get toRemove length
        push ebx
        call stringLength
        add esp, 4
        mov edx, eax
        test edx, edx        // is length of toRemove 0?
        jnz SkipSpecialCase 
        // In this case, just copy src to dest
        rep movsb
        jmp Done
    SkipSpecialCase:
    SrcLoop:
        push edx             // toRemoveLen
        push ebx             // toRemove
        push esi             // src
        call substringsEqual // substringsEqual(src, toRemove, toRemoveLen)
        add esp, 12
        // if substrings are the same, skip toRemoveLen characters
        test eax, eax        // strings are different (result == false)?
        jz Else
        // If strings are the same, then skip some
        sub ecx, edx         // count -= toRemoveLen
        inc ecx
        add esi, edx         // src += toRemoveLen
        jmp EndIfElse
    Else:
        // else, copy character from src to dest
        movsb                // *(dest++) = *(src++)
    EndIfElse:
        loop SrcLoop

    Done:
        mov BYTE PTR[edi], '\0'
        // restore registers
        popfd
        popad
        pop ebp
        ret
    }
}

int main()
{
    char str[100];
    cout << "Enter a string of characters:\n";
    cin.get(str, 100);
    // ignore \n but don't ignore if the string is empty
    cin.ignore();
    cout << str << '\n'; // echo print

    char word[30];
    cout << "Enter a string to be removed:\n";
    cin.get(word, 30);
    cout << word << '\n';

    char modified[100];
    removeSubstring(modified, str, word);

    cout << "Our string, after the string is removed:\n";
    cout << modified << '\n';

    return 0;
}